Mercurial > libervia-backend
comparison sat_frontends/jp/cmd_pubsub.py @ 3573:813595f88612
merge changes from main branch
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 17 Jun 2021 13:05:58 +0200 |
parents | 04283582966f |
children | 5f65f4e9f8cb |
comparison
equal
deleted
inserted
replaced
3541:888109774673 | 3573:813595f88612 |
---|---|
80 self.args.service, | 80 self.args.service, |
81 self.args.node, | 81 self.args.node, |
82 self.profile, | 82 self.profile, |
83 ) | 83 ) |
84 except BridgeException as e: | 84 except BridgeException as e: |
85 if e.condition == 'item-not-found': | 85 if e.condition == "item-not-found": |
86 self.disp( | 86 self.disp( |
87 f"The node {self.args.node} doesn't exist on {self.args.service}", | 87 f"The node {self.args.node} doesn't exist on {self.args.service}", |
88 error=True | 88 error=True, |
89 ) | 89 ) |
90 self.host.quit(C.EXIT_NOT_FOUND) | 90 self.host.quit(C.EXIT_NOT_FOUND) |
91 else: | 91 else: |
92 self.disp(f"can't get node configuration: {e}", error=True) | 92 self.disp(f"can't get node configuration: {e}", error=True) |
93 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 93 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
153 self.args.node, | 153 self.args.node, |
154 options, | 154 options, |
155 self.profile, | 155 self.profile, |
156 ) | 156 ) |
157 except Exception as e: | 157 except Exception as e: |
158 self.disp(msg=_(f"can't create node: {e}"), error=True) | 158 self.disp(msg=_("can't create node: {e}").format(e=e), error=True) |
159 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 159 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
160 else: | 160 else: |
161 if self.host.verbosity: | 161 if self.host.verbosity: |
162 announce = _("node created successfully: ") | 162 announce = _("node created successfully: ") |
163 else: | 163 else: |
165 self.disp(announce + node_id) | 165 self.disp(announce + node_id) |
166 self.host.quit() | 166 self.host.quit() |
167 | 167 |
168 | 168 |
169 class NodePurge(base.CommandBase): | 169 class NodePurge(base.CommandBase): |
170 | |
171 def __init__(self, host): | 170 def __init__(self, host): |
172 super(NodePurge, self).__init__( | 171 super(NodePurge, self).__init__( |
173 host, | 172 host, |
174 "purge", | 173 "purge", |
175 use_pubsub=True, | 174 use_pubsub=True, |
187 | 186 |
188 async def start(self): | 187 async def start(self): |
189 if not self.args.force: | 188 if not self.args.force: |
190 if not self.args.service: | 189 if not self.args.service: |
191 message = _( | 190 message = _( |
192 f"Are you sure to purge PEP node [{self.args.node}]? This will " | 191 "Are you sure to purge PEP node [{node}]? This will " |
193 f"delete ALL items from it!") | 192 "delete ALL items from it!" |
193 ).format(node=self.args.node) | |
194 else: | 194 else: |
195 message = _( | 195 message = _( |
196 f"Are you sure to delete node [{self.args.node}] on service " | 196 "Are you sure to delete node [{node}] on service " |
197 f"[{self.args.service}]? This will delete ALL items from it!") | 197 "[{service}]? This will delete ALL items from it!" |
198 ).format(node=self.args.node, service=self.args.service) | |
198 await self.host.confirmOrQuit(message, _("node purge cancelled")) | 199 await self.host.confirmOrQuit(message, _("node purge cancelled")) |
199 | 200 |
200 try: | 201 try: |
201 await self.host.bridge.psNodePurge( | 202 await self.host.bridge.psNodePurge( |
202 self.args.service, | 203 self.args.service, |
203 self.args.node, | 204 self.args.node, |
204 self.profile, | 205 self.profile, |
205 ) | 206 ) |
206 except Exception as e: | 207 except Exception as e: |
207 self.disp(msg=_(f"can't purge node: {e}"), error=True) | 208 self.disp(msg=_("can't purge node: {e}").format(e=e), error=True) |
208 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 209 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
209 else: | 210 else: |
210 self.disp(_(f"node [{self.args.node}] purged successfully")) | 211 self.disp(_("node [{node}] purged successfully").format(node=self.args.node)) |
211 self.host.quit() | 212 self.host.quit() |
212 | 213 |
213 | 214 |
214 class NodeDelete(base.CommandBase): | 215 class NodeDelete(base.CommandBase): |
215 def __init__(self, host): | 216 def __init__(self, host): |
231 ) | 232 ) |
232 | 233 |
233 async def start(self): | 234 async def start(self): |
234 if not self.args.force: | 235 if not self.args.force: |
235 if not self.args.service: | 236 if not self.args.service: |
236 message = _(f"Are you sure to delete PEP node [{self.args.node}] ?") | 237 message = _("Are you sure to delete PEP node [{node}] ?").format( |
238 node=self.args.node | |
239 ) | |
237 else: | 240 else: |
238 message = _(f"Are you sure to delete node [{self.args.node}] on " | 241 message = _( |
239 f"service [{self.args.service}]?") | 242 "Are you sure to delete node [{node}] on " "service [{service}]?" |
243 ).format(node=self.args.node, service=self.args.service) | |
240 await self.host.confirmOrQuit(message, _("node deletion cancelled")) | 244 await self.host.confirmOrQuit(message, _("node deletion cancelled")) |
241 | 245 |
242 try: | 246 try: |
243 await self.host.bridge.psNodeDelete( | 247 await self.host.bridge.psNodeDelete( |
244 self.args.service, | 248 self.args.service, |
247 ) | 251 ) |
248 except Exception as e: | 252 except Exception as e: |
249 self.disp(f"can't delete node: {e}", error=True) | 253 self.disp(f"can't delete node: {e}", error=True) |
250 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 254 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
251 else: | 255 else: |
252 self.disp(_(f"node [{self.args.node}] deleted successfully")) | 256 self.disp(_("node [{node}] deleted successfully").format(node=self.args.node)) |
253 self.host.quit() | 257 self.host.quit() |
254 | 258 |
255 | 259 |
256 class NodeSet(base.CommandBase): | 260 class NodeSet(base.CommandBase): |
257 def __init__(self, host): | 261 def __init__(self, host): |
305 self.disp(_("node configuration successful"), 1) | 309 self.disp(_("node configuration successful"), 1) |
306 self.host.quit() | 310 self.host.quit() |
307 | 311 |
308 | 312 |
309 class NodeImport(base.CommandBase): | 313 class NodeImport(base.CommandBase): |
310 | |
311 def __init__(self, host): | 314 def __init__(self, host): |
312 super(NodeImport, self).__init__( | 315 super(NodeImport, self).__init__( |
313 host, | 316 host, |
314 "import", | 317 "import", |
315 use_pubsub=True, | 318 use_pubsub=True, |
324 help=_("do a pubsub admin request, needed to change publisher"), | 327 help=_("do a pubsub admin request, needed to change publisher"), |
325 ) | 328 ) |
326 self.parser.add_argument( | 329 self.parser.add_argument( |
327 "import_file", | 330 "import_file", |
328 type=argparse.FileType(), | 331 type=argparse.FileType(), |
329 help=_("path to the XML file with data to import. The file must contain " | 332 help=_( |
330 "whole XML of each item to import."), | 333 "path to the XML file with data to import. The file must contain " |
331 ) | 334 "whole XML of each item to import." |
332 | 335 ), |
333 async def start(self): | 336 ) |
334 try: | 337 |
335 element, etree = xml_tools.etreeParse(self, self.args.import_file, | 338 async def start(self): |
336 reraise=True) | 339 try: |
340 element, etree = xml_tools.etreeParse( | |
341 self, self.args.import_file, reraise=True | |
342 ) | |
337 except Exception as e: | 343 except Exception as e: |
338 from lxml.etree import XMLSyntaxError | 344 from lxml.etree import XMLSyntaxError |
345 | |
339 if isinstance(e, XMLSyntaxError) and e.code == 5: | 346 if isinstance(e, XMLSyntaxError) and e.code == 5: |
340 # we have extra content, this probaby means that item are not wrapped | 347 # we have extra content, this probaby means that item are not wrapped |
341 # so we wrap them here and try again | 348 # so we wrap them here and try again |
342 self.args.import_file.seek(0) | 349 self.args.import_file.seek(0) |
343 xml_buf = "<import>" + self.args.import_file.read() + "</import>" | 350 xml_buf = "<import>" + self.args.import_file.read() + "</import>" |
344 element, etree = xml_tools.etreeParse(self, xml_buf) | 351 element, etree = xml_tools.etreeParse(self, xml_buf) |
345 | 352 |
346 # we reverse element as we expect to have most recently published element first | 353 # we reverse element as we expect to have most recently published element first |
347 # TODO: make this more explicit and add an option | 354 # TODO: make this more explicit and add an option |
348 element[:] = reversed(element) | 355 element[:] = reversed(element) |
349 | 356 |
350 if not all([i.tag == '{http://jabber.org/protocol/pubsub}item' for i in element]): | 357 if not all([i.tag == "{http://jabber.org/protocol/pubsub}item" for i in element]): |
351 self.disp( | 358 self.disp( |
352 _("You are not using list of pubsub items, we can't import this file"), | 359 _("You are not using list of pubsub items, we can't import this file"), |
353 error=True) | 360 error=True, |
361 ) | |
354 self.host.quit(C.EXIT_DATA_ERROR) | 362 self.host.quit(C.EXIT_DATA_ERROR) |
355 return | 363 return |
356 | 364 |
357 items = [etree.tostring(i, encoding="unicode") for i in element] | 365 items = [etree.tostring(i, encoding="unicode") for i in element] |
358 if self.args.admin: | 366 if self.args.admin: |
359 method = self.host.bridge.psAdminItemsSend | 367 method = self.host.bridge.psAdminItemsSend |
360 else: | 368 else: |
361 self.disp(_("Items are imported without using admin mode, publisher can't " | 369 self.disp( |
362 "be changed")) | 370 _( |
371 "Items are imported without using admin mode, publisher can't " | |
372 "be changed" | |
373 ) | |
374 ) | |
363 method = self.host.bridge.psItemsSend | 375 method = self.host.bridge.psItemsSend |
364 | 376 |
365 try: | 377 try: |
366 items_ids = await method( | 378 items_ids = await method( |
367 self.args.service, | 379 self.args.service, |
373 except Exception as e: | 385 except Exception as e: |
374 self.disp(f"can't send items: {e}", error=True) | 386 self.disp(f"can't send items: {e}", error=True) |
375 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 387 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
376 else: | 388 else: |
377 if items_ids: | 389 if items_ids: |
378 self.disp(_('items published with id(s) {items_ids}').format( | 390 self.disp( |
379 items_ids=', '.join(items_ids))) | 391 _("items published with id(s) {items_ids}").format( |
392 items_ids=", ".join(items_ids) | |
393 ) | |
394 ) | |
380 else: | 395 else: |
381 self.disp(_('items published')) | 396 self.disp(_("items published")) |
382 self.host.quit() | 397 self.host.quit() |
383 | 398 |
384 | 399 |
385 class NodeAffiliationsGet(base.CommandBase): | 400 class NodeAffiliationsGet(base.CommandBase): |
386 def __init__(self, host): | 401 def __init__(self, host): |
643 | 658 |
644 async def psSchemaGetCb(self, schema): | 659 async def psSchemaGetCb(self, schema): |
645 try: | 660 try: |
646 from lxml import etree | 661 from lxml import etree |
647 except ImportError: | 662 except ImportError: |
648 self.disp('lxml module must be installed to use edit, please install it ' | 663 self.disp( |
649 'with "pip install lxml"', | 664 "lxml module must be installed to use edit, please install it " |
665 'with "pip install lxml"', | |
650 error=True, | 666 error=True, |
651 ) | 667 ) |
652 self.host.quit(1) | 668 self.host.quit(1) |
653 content_file_obj, content_file_path = self.getTmpFile() | 669 content_file_obj, content_file_path = self.getTmpFile() |
654 schema = schema.strip() | 670 schema = schema.strip() |
657 schema_elt = etree.fromstring(schema, parser) | 673 schema_elt = etree.fromstring(schema, parser) |
658 content_file_obj.write( | 674 content_file_obj.write( |
659 etree.tostring(schema_elt, encoding="utf-8", pretty_print=True) | 675 etree.tostring(schema_elt, encoding="utf-8", pretty_print=True) |
660 ) | 676 ) |
661 content_file_obj.seek(0) | 677 content_file_obj.seek(0) |
662 await self.runEditor("pubsub_schema_editor_args", content_file_path, content_file_obj) | 678 await self.runEditor( |
679 "pubsub_schema_editor_args", content_file_path, content_file_obj | |
680 ) | |
663 | 681 |
664 async def start(self): | 682 async def start(self): |
665 try: | 683 try: |
666 schema = await self.host.bridge.psSchemaGet( | 684 schema = await self.host.bridge.psSchemaGet( |
667 self.args.service, | 685 self.args.service, |
668 self.args.node, | 686 self.args.node, |
669 self.profile, | 687 self.profile, |
670 ) | 688 ) |
671 except BridgeException as e: | 689 except BridgeException as e: |
672 if e.condition == 'item-not-found' or e.classname=="NotFound": | 690 if e.condition == "item-not-found" or e.classname == "NotFound": |
673 schema = "" | 691 schema = "" |
674 else: | 692 else: |
675 self.disp(f"can't edit schema: {e}", error=True) | 693 self.disp(f"can't edit schema: {e}", error=True) |
676 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 694 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
677 | 695 |
700 self.args.service, | 718 self.args.service, |
701 self.args.node, | 719 self.args.node, |
702 self.profile, | 720 self.profile, |
703 ) | 721 ) |
704 except BridgeException as e: | 722 except BridgeException as e: |
705 if e.condition == 'item-not-found' or e.classname=="NotFound": | 723 if e.condition == "item-not-found" or e.classname == "NotFound": |
706 schema = None | 724 schema = None |
707 else: | 725 else: |
708 self.disp(f"can't get schema: {e}", error=True) | 726 self.disp(f"can't get schema: {e}", error=True) |
709 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 727 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
710 | 728 |
770 element = xml_tools.getPayload(self, element) | 788 element = xml_tools.getPayload(self, element) |
771 payload = etree.tostring(element, encoding="unicode") | 789 payload = etree.tostring(element, encoding="unicode") |
772 extra = {} | 790 extra = {} |
773 publish_options = NodeCreate.get_config_options(self.args) | 791 publish_options = NodeCreate.get_config_options(self.args) |
774 if publish_options: | 792 if publish_options: |
775 extra['publish_options'] = publish_options | 793 extra["publish_options"] = publish_options |
776 | 794 |
777 try: | 795 try: |
778 published_id = await self.host.bridge.psItemSend( | 796 published_id = await self.host.bridge.psItemSend( |
779 self.args.service, | 797 self.args.service, |
780 self.args.node, | 798 self.args.node, |
782 self.args.item, | 800 self.args.item, |
783 data_format.serialise(extra), | 801 data_format.serialise(extra), |
784 self.profile, | 802 self.profile, |
785 ) | 803 ) |
786 except Exception as e: | 804 except Exception as e: |
787 self.disp(_(f"can't send item: {e}"), error=True) | 805 self.disp(_("can't send item: {e}").format(e=e), error=True) |
788 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 806 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
789 else: | 807 else: |
790 if published_id: | 808 if published_id: |
791 if self.args.quiet: | 809 if self.args.quiet: |
792 self.disp(published_id, end='') | 810 self.disp(published_id, end="") |
793 else: | 811 else: |
794 self.disp(f"Item published at {published_id}") | 812 self.disp(f"Item published at {published_id}") |
795 else: | 813 else: |
796 self.disp("Item published") | 814 self.disp("Item published") |
797 self.host.quit(C.EXIT_OK) | 815 self.host.quit(C.EXIT_OK) |
831 self.getPubsubExtra(), | 849 self.getPubsubExtra(), |
832 self.profile, | 850 self.profile, |
833 ) | 851 ) |
834 ) | 852 ) |
835 except BridgeException as e: | 853 except BridgeException as e: |
836 if e.condition == 'item-not-found' or e.classname=="NotFound": | 854 if e.condition == "item-not-found" or e.classname == "NotFound": |
837 self.disp( | 855 self.disp( |
838 f"The node {self.args.node} doesn't exist on {self.args.service}", | 856 f"The node {self.args.node} doesn't exist on {self.args.service}", |
839 error=True | 857 error=True, |
840 ) | 858 ) |
841 self.host.quit(C.EXIT_NOT_FOUND) | 859 self.host.quit(C.EXIT_NOT_FOUND) |
842 else: | 860 else: |
843 self.disp(f"can't get pubsub items: {e}", error=True) | 861 self.disp(f"can't get pubsub items: {e}", error=True) |
844 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 862 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
845 except Exception as e: | 863 except Exception as e: |
846 self.disp(f"Internal error: {e}", error=True) | 864 self.disp(f"Internal error: {e}", error=True) |
847 self.host.quit(C.EXIT_INTERNAL_ERROR) | 865 self.host.quit(C.EXIT_INTERNAL_ERROR) |
848 else: | 866 else: |
849 await self.output(ps_result['items']) | 867 await self.output(ps_result["items"]) |
850 self.host.quit(C.EXIT_OK) | 868 self.host.quit(C.EXIT_OK) |
851 | 869 |
852 | 870 |
853 class Delete(base.CommandBase): | 871 class Delete(base.CommandBase): |
854 def __init__(self, host): | 872 def __init__(self, host): |
884 self.args.item, | 902 self.args.item, |
885 self.args.notify, | 903 self.args.notify, |
886 self.profile, | 904 self.profile, |
887 ) | 905 ) |
888 except Exception as e: | 906 except Exception as e: |
889 self.disp(_(f"can't delete item: {e}"), error=True) | 907 self.disp(_("can't delete item: {e}").format(e=e), error=True) |
890 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 908 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
891 else: | 909 else: |
892 self.disp(_(f"item {self.args.item} has been deleted")) | 910 self.disp(_("item {item} has been deleted").format(item=self.args.item)) |
893 self.host.quit(C.EXIT_OK) | 911 self.host.quit(C.EXIT_OK) |
894 | 912 |
895 | 913 |
896 class Edit(base.CommandBase, common.BaseEdit): | 914 class Edit(base.CommandBase, common.BaseEdit): |
897 def __init__(self, host): | 915 def __init__(self, host): |
926 | 944 |
927 async def getItemData(self, service, node, item): | 945 async def getItemData(self, service, node, item): |
928 try: | 946 try: |
929 from lxml import etree | 947 from lxml import etree |
930 except ImportError: | 948 except ImportError: |
931 self.disp('lxml module must be installed to use edit, please install it ' | 949 self.disp( |
932 'with "pip install lxml"', | 950 "lxml module must be installed to use edit, please install it " |
951 'with "pip install lxml"', | |
933 error=True, | 952 error=True, |
934 ) | 953 ) |
935 self.host.quit(1) | 954 self.host.quit(1) |
936 items = [item] if item else [] | 955 items = [item] if item else [] |
937 ps_result = data_format.deserialise( | 956 ps_result = data_format.deserialise( |
938 await self.host.bridge.psItemsGet( | 957 await self.host.bridge.psItemsGet( |
939 service, node, 1, items, "", {}, self.profile | 958 service, node, 1, items, "", {}, self.profile |
940 ) | 959 ) |
941 ) | 960 ) |
942 item_raw = ps_result['items'][0] | 961 item_raw = ps_result["items"][0] |
943 parser = etree.XMLParser(remove_blank_text=True, recover=True) | 962 parser = etree.XMLParser(remove_blank_text=True, recover=True) |
944 item_elt = etree.fromstring(item_raw, parser) | 963 item_elt = etree.fromstring(item_raw, parser) |
945 item_id = item_elt.get("id") | 964 item_id = item_elt.get("id") |
946 try: | 965 try: |
947 payload = item_elt[0] | 966 payload = item_elt[0] |
949 self.disp(_("Item has not payload"), 1) | 968 self.disp(_("Item has not payload"), 1) |
950 return "", item_id | 969 return "", item_id |
951 return etree.tostring(payload, encoding="unicode", pretty_print=True), item_id | 970 return etree.tostring(payload, encoding="unicode", pretty_print=True), item_id |
952 | 971 |
953 async def start(self): | 972 async def start(self): |
954 (self.pubsub_service, | 973 ( |
955 self.pubsub_node, | 974 self.pubsub_service, |
956 self.pubsub_item, | 975 self.pubsub_node, |
957 content_file_path, | 976 self.pubsub_item, |
958 content_file_obj) = await self.getItemPath() | 977 content_file_path, |
978 content_file_obj, | |
979 ) = await self.getItemPath() | |
959 await self.runEditor("pubsub_editor_args", content_file_path, content_file_obj) | 980 await self.runEditor("pubsub_editor_args", content_file_path, content_file_obj) |
960 self.host.quit() | 981 self.host.quit() |
961 | 982 |
962 | 983 |
963 class Rename(base.CommandBase): | 984 class Rename(base.CommandBase): |
964 | |
965 def __init__(self, host): | 985 def __init__(self, host): |
966 base.CommandBase.__init__( | 986 base.CommandBase.__init__( |
967 self, | 987 self, |
968 host, | 988 host, |
969 "rename", | 989 "rename", |
971 pubsub_flags={C.NODE, C.SINGLE_ITEM}, | 991 pubsub_flags={C.NODE, C.SINGLE_ITEM}, |
972 help=_("rename a pubsub item"), | 992 help=_("rename a pubsub item"), |
973 ) | 993 ) |
974 | 994 |
975 def add_parser_options(self): | 995 def add_parser_options(self): |
976 self.parser.add_argument( | 996 self.parser.add_argument("new_id", help=_("new item id to use")) |
977 "new_id", | |
978 help=_("new item id to use") | |
979 ) | |
980 | 997 |
981 async def start(self): | 998 async def start(self): |
982 try: | 999 try: |
983 await self.host.bridge.psItemRename( | 1000 await self.host.bridge.psItemRename( |
984 self.args.service, | 1001 self.args.service, |
986 self.args.item, | 1003 self.args.item, |
987 self.args.new_id, | 1004 self.args.new_id, |
988 self.profile, | 1005 self.profile, |
989 ) | 1006 ) |
990 except Exception as e: | 1007 except Exception as e: |
991 self.disp( | 1008 self.disp(f"can't rename item: {e}", error=True) |
992 f"can't rename item: {e}", error=True | |
993 ) | |
994 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1009 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
995 else: | 1010 else: |
996 self.disp("Item renamed") | 1011 self.disp("Item renamed") |
997 self.host.quit(C.EXIT_OK) | 1012 self.host.quit(C.EXIT_OK) |
998 | 1013 |
1019 self.args.node, | 1034 self.args.node, |
1020 {}, | 1035 {}, |
1021 self.profile, | 1036 self.profile, |
1022 ) | 1037 ) |
1023 except Exception as e: | 1038 except Exception as e: |
1024 self.disp(_(f"can't subscribe to node: {e}"), error=True) | 1039 self.disp(_("can't subscribe to node: {e}").format(e=e), error=True) |
1025 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1040 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
1026 else: | 1041 else: |
1027 self.disp(_("subscription done"), 1) | 1042 self.disp(_("subscription done"), 1) |
1028 if sub_id: | 1043 if sub_id: |
1029 self.disp(_("subscription id: {sub_id}").format(sub_id=sub_id)) | 1044 self.disp(_("subscription id: {sub_id}").format(sub_id=sub_id)) |
1053 self.args.service, | 1068 self.args.service, |
1054 self.args.node, | 1069 self.args.node, |
1055 self.profile, | 1070 self.profile, |
1056 ) | 1071 ) |
1057 except Exception as e: | 1072 except Exception as e: |
1058 self.disp(_(f"can't unsubscribe from node: {e}"), error=True) | 1073 self.disp(_("can't unsubscribe from node: {e}").format(e=e), error=True) |
1059 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1074 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
1060 else: | 1075 else: |
1061 self.disp(_("subscription removed"), 1) | 1076 self.disp(_("subscription removed"), 1) |
1062 self.host.quit() | 1077 self.host.quit() |
1063 | 1078 |
1082 self.args.service, | 1097 self.args.service, |
1083 self.args.node, | 1098 self.args.node, |
1084 self.profile, | 1099 self.profile, |
1085 ) | 1100 ) |
1086 except Exception as e: | 1101 except Exception as e: |
1087 self.disp(_(f"can't retrieve subscriptions: {e}"), error=True) | 1102 self.disp(_("can't retrieve subscriptions: {e}").format(e=e), error=True) |
1088 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1103 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
1089 else: | 1104 else: |
1090 await self.output(subscriptions) | 1105 await self.output(subscriptions) |
1091 self.host.quit() | 1106 self.host.quit() |
1092 | 1107 |
1111 self.args.service, | 1126 self.args.service, |
1112 self.args.node, | 1127 self.args.node, |
1113 self.profile, | 1128 self.profile, |
1114 ) | 1129 ) |
1115 except Exception as e: | 1130 except Exception as e: |
1116 self.disp( | 1131 self.disp(f"can't get node affiliations: {e}", error=True) |
1117 f"can't get node affiliations: {e}", error=True | |
1118 ) | |
1119 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1132 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
1120 else: | 1133 else: |
1121 await self.output(affiliations) | 1134 await self.output(affiliations) |
1122 self.host.quit() | 1135 self.host.quit() |
1123 | 1136 |
1167 self.parser.add_argument( | 1180 self.parser.add_argument( |
1168 "-D", | 1181 "-D", |
1169 "--max-depth", | 1182 "--max-depth", |
1170 type=int, | 1183 type=int, |
1171 default=0, | 1184 default=0, |
1172 help=_("maximum depth of recursion (will search linked nodes if > 0, " | 1185 help=_( |
1173 "DEFAULT: 0)"), | 1186 "maximum depth of recursion (will search linked nodes if > 0, " |
1187 "DEFAULT: 0)" | |
1188 ), | |
1174 ) | 1189 ) |
1175 self.parser.add_argument( | 1190 self.parser.add_argument( |
1176 "-M", | 1191 "-M", |
1177 "--node-max", | 1192 "--node-max", |
1178 type=int, | 1193 type=int, |
1179 default=30, | 1194 default=30, |
1180 help=_("maximum number of items to get per node ({} to get all items, " | 1195 help=_( |
1181 "DEFAULT: 30)".format( C.NO_LIMIT)), | 1196 "maximum number of items to get per node ({} to get all items, " |
1197 "DEFAULT: 30)".format(C.NO_LIMIT) | |
1198 ), | |
1182 ) | 1199 ) |
1183 self.parser.add_argument( | 1200 self.parser.add_argument( |
1184 "-N", | 1201 "-N", |
1185 "--namespace", | 1202 "--namespace", |
1186 action="append", | 1203 action="append", |
1231 "--python", | 1248 "--python", |
1232 action="append", | 1249 action="append", |
1233 dest="filters", | 1250 dest="filters", |
1234 type=filter_python, | 1251 type=filter_python, |
1235 metavar="PYTHON_CODE", | 1252 metavar="PYTHON_CODE", |
1236 help=_('Python expression which much return a bool (True to keep item, ' | 1253 help=_( |
1237 'False to reject it). "item" is raw text item, "item_xml" is ' | 1254 "Python expression which much return a bool (True to keep item, " |
1238 'lxml\'s etree.Element' | 1255 'False to reject it). "item" is raw text item, "item_xml" is ' |
1256 "lxml's etree.Element" | |
1239 ), | 1257 ), |
1240 ) | 1258 ) |
1241 | 1259 |
1242 # filters flags | 1260 # filters flags |
1243 flag_case = partial(self.filter_flag, type_="ignore-case") | 1261 flag_case = partial(self.filter_flag, type_="ignore-case") |
1360 def parseXml(self, item): | 1378 def parseXml(self, item): |
1361 try: | 1379 try: |
1362 return self.etree.fromstring(item) | 1380 return self.etree.fromstring(item) |
1363 except self.etree.XMLSyntaxError: | 1381 except self.etree.XMLSyntaxError: |
1364 self.disp( | 1382 self.disp( |
1365 _("item doesn't looks like XML, you have probably used --only-matching " | 1383 _( |
1366 "somewhere before and we have no more XML"), | 1384 "item doesn't looks like XML, you have probably used --only-matching " |
1385 "somewhere before and we have no more XML" | |
1386 ), | |
1367 error=True, | 1387 error=True, |
1368 ) | 1388 ) |
1369 self.host.quit(C.EXIT_BAD_ARG) | 1389 self.host.quit(C.EXIT_BAD_ARG) |
1370 | 1390 |
1371 def filter(self, item): | 1391 def filter(self, item): |
1395 keep = False | 1415 keep = False |
1396 if keep and only_matching: | 1416 if keep and only_matching: |
1397 # doesn't really make sens to keep a fixed string | 1417 # doesn't really make sens to keep a fixed string |
1398 # so we raise an error | 1418 # so we raise an error |
1399 self.host.disp( | 1419 self.host.disp( |
1400 _( | 1420 _("--only-matching used with fixed --text string, are you sure?"), |
1401 "--only-matching used with fixed --text string, are you sure?" | |
1402 ), | |
1403 error=True, | 1421 error=True, |
1404 ) | 1422 ) |
1405 self.host.quit(C.EXIT_BAD_ARG) | 1423 self.host.quit(C.EXIT_BAD_ARG) |
1406 elif type_ == "regex": | 1424 elif type_ == "regex": |
1407 flags = self.RE_FLAGS | 1425 flags = self.RE_FLAGS |
1418 if item_xml is None: | 1436 if item_xml is None: |
1419 item_xml = self.parseXml(item) | 1437 item_xml = self.parseXml(item) |
1420 try: | 1438 try: |
1421 elts = item_xml.xpath(value, namespaces=self.args.namespace) | 1439 elts = item_xml.xpath(value, namespaces=self.args.namespace) |
1422 except self.etree.XPathEvalError as e: | 1440 except self.etree.XPathEvalError as e: |
1423 self.disp( | 1441 self.disp(_("can't use xpath: {reason}").format(reason=e), error=True) |
1424 _("can't use xpath: {reason}").format(reason=e), error=True | |
1425 ) | |
1426 self.host.quit(C.EXIT_BAD_ARG) | 1442 self.host.quit(C.EXIT_BAD_ARG) |
1427 keep = bool(elts) | 1443 keep = bool(elts) |
1428 if keep and only_matching: | 1444 if keep and only_matching: |
1429 item_xml = elts[0] | 1445 item_xml = elts[0] |
1430 try: | 1446 try: |
1434 item = str(item_xml) | 1450 item = str(item_xml) |
1435 item_xml = None | 1451 item_xml = None |
1436 elif type_ == "python": | 1452 elif type_ == "python": |
1437 if item_xml is None: | 1453 if item_xml is None: |
1438 item_xml = self.parseXml(item) | 1454 item_xml = self.parseXml(item) |
1439 cmd_ns = { | 1455 cmd_ns = {"etree": self.etree, "item": item, "item_xml": item_xml} |
1440 "etree": self.etree, | |
1441 "item": item, | |
1442 "item_xml": item_xml | |
1443 } | |
1444 try: | 1456 try: |
1445 keep = eval(value, cmd_ns) | 1457 keep = eval(value, cmd_ns) |
1446 except SyntaxError as e: | 1458 except SyntaxError as e: |
1447 self.disp(str(e), error=True) | 1459 self.disp(str(e), error=True) |
1448 self.host.quit(C.EXIT_BAD_ARG) | 1460 self.host.quit(C.EXIT_BAD_ARG) |
1449 | 1461 |
1450 ## flags | 1462 ## flags |
1451 | 1463 |
1452 elif type_ == "ignore-case": | 1464 elif type_ == "ignore-case": |
1453 ignore_case = value | 1465 ignore_case = value |
1454 elif type_ == "invert": | 1466 elif type_ == "invert": |
1455 invert = value | 1467 invert = value |
1510 ) | 1522 ) |
1511 if action == "exec": | 1523 if action == "exec": |
1512 p = await asyncio.create_subprocess_exec(*cmd_args) | 1524 p = await asyncio.create_subprocess_exec(*cmd_args) |
1513 ret = await p.wait() | 1525 ret = await p.wait() |
1514 else: | 1526 else: |
1515 p = await asyncio.create_subprocess_exec(*cmd_args, | 1527 p = await asyncio.create_subprocess_exec(*cmd_args, stdin=subprocess.PIPE) |
1516 stdin=subprocess.PIPE) | |
1517 await p.communicate(item.encode(sys.getfilesystemencoding())) | 1528 await p.communicate(item.encode(sys.getfilesystemencoding())) |
1518 ret = p.returncode | 1529 ret = p.returncode |
1519 if ret != 0: | 1530 if ret != 0: |
1520 self.disp( | 1531 self.disp( |
1521 A.color( | 1532 A.color( |
1522 C.A_FAILURE, | 1533 C.A_FAILURE, |
1523 _(f"executed command failed with exit code {ret}"), | 1534 _("executed command failed with exit code {ret}").format(ret=ret), |
1524 ) | 1535 ) |
1525 ) | 1536 ) |
1526 | 1537 |
1527 async def search(self, ps_result, depth): | 1538 async def search(self, ps_result, depth): |
1528 """callback of getItems | 1539 """callback of getItems |
1531 do the requested action, and exit the command when everything is done | 1542 do the requested action, and exit the command when everything is done |
1532 @param items_data(tuple): result of getItems | 1543 @param items_data(tuple): result of getItems |
1533 @param depth(int): current depth level | 1544 @param depth(int): current depth level |
1534 0 for first node, 1 for first children, and so on | 1545 0 for first node, 1 for first children, and so on |
1535 """ | 1546 """ |
1536 for item in ps_result['items']: | 1547 for item in ps_result["items"]: |
1537 if depth < self.args.max_depth: | 1548 if depth < self.args.max_depth: |
1538 await self.getSubNodes(item, depth) | 1549 await self.getSubNodes(item, depth) |
1539 keep, item = self.filter(item) | 1550 keep, item = self.filter(item) |
1540 if not keep: | 1551 if not keep: |
1541 continue | 1552 continue |
1542 await self.doItemAction(item, ps_result) | 1553 await self.doItemAction(item, ps_result) |
1543 | 1554 |
1544 # we check if we got all getItems results | 1555 # we check if we got all getItems results |
1545 self.to_get -= 1 | 1556 self.to_get -= 1 |
1546 if self.to_get == 0: | 1557 if self.to_get == 0: |
1547 # yes, we can quit | 1558 # yes, we can quit |
1548 self.host.quit() | 1559 self.host.quit() |
1549 assert self.to_get > 0 | 1560 assert self.to_get > 0 |
1560 if self.args.action in self.EXEC_ACTIONS: | 1571 if self.args.action in self.EXEC_ACTIONS: |
1561 self.parser.error(_("you need to specify a command to execute")) | 1572 self.parser.error(_("you need to specify a command to execute")) |
1562 if not self.args.node: | 1573 if not self.args.node: |
1563 # TODO: handle get service affiliations when node is not set | 1574 # TODO: handle get service affiliations when node is not set |
1564 self.parser.error(_("empty node is not handled yet")) | 1575 self.parser.error(_("empty node is not handled yet")) |
1565 # to_get is increased on each get and decreased on each answer | 1576 # to_get is increased on each get and decreased on each answer |
1566 # when it reach 0 again, the command is finished | 1577 # when it reach 0 again, the command is finished |
1567 self.to_get = 0 | 1578 self.to_get = 0 |
1568 self._etree = None | 1579 self._etree = None |
1569 if self.args.filters is None: | 1580 if self.args.filters is None: |
1570 self.args.filters = [] | 1581 self.args.filters = [] |
1571 self.args.namespace = dict( | 1582 self.args.namespace = dict( |
1599 self.parser.add_argument( | 1610 self.parser.add_argument( |
1600 "-I", | 1611 "-I", |
1601 "--ignore-errors", | 1612 "--ignore-errors", |
1602 action="store_true", | 1613 action="store_true", |
1603 help=_( | 1614 help=_( |
1604 "if command return a non zero exit code, ignore the item and continue"), | 1615 "if command return a non zero exit code, ignore the item and continue" |
1616 ), | |
1605 ) | 1617 ) |
1606 self.parser.add_argument( | 1618 self.parser.add_argument( |
1607 "-A", | 1619 "-A", |
1608 "--all", | 1620 "--all", |
1609 action="store_true", | 1621 action="store_true", |
1610 help=_("get all items by looping over all pages using RSM") | 1622 help=_("get all items by looping over all pages using RSM"), |
1611 ) | 1623 ) |
1612 self.parser.add_argument( | 1624 self.parser.add_argument( |
1613 "command_path", | 1625 "command_path", |
1614 help=_("path to the command to use. Will be called repetitivly with an " | 1626 help=_( |
1615 "item as input. Output (full item XML) will be used as new one. " | 1627 "path to the command to use. Will be called repetitivly with an " |
1616 'Return "DELETE" string to delete the item, and "SKIP" to ignore it'), | 1628 "item as input. Output (full item XML) will be used as new one. " |
1629 'Return "DELETE" string to delete the item, and "SKIP" to ignore it' | |
1630 ), | |
1617 ) | 1631 ) |
1618 | 1632 |
1619 async def psItemsSendCb(self, item_ids, metadata): | 1633 async def psItemsSendCb(self, item_ids, metadata): |
1620 if item_ids: | 1634 if item_ids: |
1621 self.disp(_('items published with ids {item_ids}').format( | 1635 self.disp( |
1622 item_ids=', '.join(item_ids))) | 1636 _("items published with ids {item_ids}").format( |
1623 else: | 1637 item_ids=", ".join(item_ids) |
1624 self.disp(_('items published')) | 1638 ) |
1639 ) | |
1640 else: | |
1641 self.disp(_("items published")) | |
1625 if self.args.all: | 1642 if self.args.all: |
1626 return await self.handleNextPage(metadata) | 1643 return await self.handleNextPage(metadata) |
1627 else: | 1644 else: |
1628 self.host.quit() | 1645 self.host.quit() |
1629 | 1646 |
1632 | 1649 |
1633 use to handle --all option | 1650 use to handle --all option |
1634 @param metadata(dict): metadata as returned by psItemsGet | 1651 @param metadata(dict): metadata as returned by psItemsGet |
1635 """ | 1652 """ |
1636 try: | 1653 try: |
1637 last = metadata['rsm']['last'] | 1654 last = metadata["rsm"]["last"] |
1638 index = int(metadata['rsm']['index']) | 1655 index = int(metadata["rsm"]["index"]) |
1639 count = int(metadata['rsm']['count']) | 1656 count = int(metadata["rsm"]["count"]) |
1640 except KeyError: | 1657 except KeyError: |
1641 self.disp(_("Can't retrieve all items, RSM metadata not available"), | 1658 self.disp( |
1642 error=True) | 1659 _("Can't retrieve all items, RSM metadata not available"), error=True |
1660 ) | |
1643 self.host.quit(C.EXIT_MISSING_FEATURE) | 1661 self.host.quit(C.EXIT_MISSING_FEATURE) |
1644 except ValueError as e: | 1662 except ValueError as e: |
1645 self.disp(_("Can't retrieve all items, bad RSM metadata: {msg}") | 1663 self.disp( |
1646 .format(msg=e), error=True) | 1664 _("Can't retrieve all items, bad RSM metadata: {msg}").format(msg=e), |
1665 error=True, | |
1666 ) | |
1647 self.host.quit(C.EXIT_ERROR) | 1667 self.host.quit(C.EXIT_ERROR) |
1648 | 1668 |
1649 if index + self.args.rsm_max >= count: | 1669 if index + self.args.rsm_max >= count: |
1650 self.disp(_('All items transformed')) | 1670 self.disp(_("All items transformed")) |
1651 self.host.quit(0) | 1671 self.host.quit(0) |
1652 | 1672 |
1653 self.disp(_('Retrieving next page ({page_idx}/{page_total})').format( | 1673 self.disp( |
1654 page_idx = int(index/self.args.rsm_max) + 1, | 1674 _("Retrieving next page ({page_idx}/{page_total})").format( |
1655 page_total = int(count/self.args.rsm_max), | 1675 page_idx=int(index / self.args.rsm_max) + 1, |
1676 page_total=int(count / self.args.rsm_max), | |
1656 ) | 1677 ) |
1657 ) | 1678 ) |
1658 | 1679 |
1659 extra = self.getPubsubExtra() | 1680 extra = self.getPubsubExtra() |
1660 extra['rsm_after'] = last | 1681 extra["rsm_after"] = last |
1661 try: | 1682 try: |
1662 ps_result = await data_format.deserialise( | 1683 ps_result = await data_format.deserialise( |
1663 self.host.bridge.psItemsGet( | 1684 self.host.bridge.psItemsGet( |
1664 self.args.service, | 1685 self.args.service, |
1665 self.args.node, | 1686 self.args.node, |
1669 extra, | 1690 extra, |
1670 self.profile, | 1691 self.profile, |
1671 ) | 1692 ) |
1672 ) | 1693 ) |
1673 except Exception as e: | 1694 except Exception as e: |
1674 self.disp( | 1695 self.disp(f"can't retrieve items: {e}", error=True) |
1675 f"can't retrieve items: {e}", error=True | |
1676 ) | |
1677 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1696 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
1678 else: | 1697 else: |
1679 await self.psItemsGetCb(ps_result) | 1698 await self.psItemsGetCb(ps_result) |
1680 | 1699 |
1681 async def psItemsGetCb(self, ps_result): | 1700 async def psItemsGetCb(self, ps_result): |
1682 encoding = 'utf-8' | 1701 encoding = "utf-8" |
1683 new_items = [] | 1702 new_items = [] |
1684 | 1703 |
1685 for item in ps_result['items']: | 1704 for item in ps_result["items"]: |
1686 if self.check_duplicates: | 1705 if self.check_duplicates: |
1687 # this is used when we are not ordering by creation | 1706 # this is used when we are not ordering by creation |
1688 # to avoid infinite loop | 1707 # to avoid infinite loop |
1689 item_elt, __ = xml_tools.etreeParse(self, item) | 1708 item_elt, __ = xml_tools.etreeParse(self, item) |
1690 item_id = item_elt.get('id') | 1709 item_id = item_elt.get("id") |
1691 if item_id in self.items_ids: | 1710 if item_id in self.items_ids: |
1692 self.disp(_( | 1711 self.disp( |
1693 "Duplicate found on item {item_id}, we have probably handled " | 1712 _( |
1694 "all items.").format(item_id=item_id)) | 1713 "Duplicate found on item {item_id}, we have probably handled " |
1714 "all items." | |
1715 ).format(item_id=item_id) | |
1716 ) | |
1695 self.host.quit() | 1717 self.host.quit() |
1696 self.items_ids.append(item_id) | 1718 self.items_ids.append(item_id) |
1697 | 1719 |
1698 # we launch the command to filter the item | 1720 # we launch the command to filter the item |
1699 try: | 1721 try: |
1700 p = await asyncio.create_subprocess_exec( | 1722 p = await asyncio.create_subprocess_exec( |
1701 self.args.command_path, | 1723 self.args.command_path, stdin=subprocess.PIPE, stdout=subprocess.PIPE |
1702 stdin=subprocess.PIPE, | 1724 ) |
1703 stdout=subprocess.PIPE) | |
1704 except OSError as e: | 1725 except OSError as e: |
1705 exit_code = C.EXIT_CMD_NOT_FOUND if e.errno == 2 else C.EXIT_ERROR | 1726 exit_code = C.EXIT_CMD_NOT_FOUND if e.errno == 2 else C.EXIT_ERROR |
1706 self.disp(f"Can't execute the command: {e}", error=True) | 1727 self.disp(f"Can't execute the command: {e}", error=True) |
1707 self.host.quit(exit_code) | 1728 self.host.quit(exit_code) |
1708 encoding = "utf-8" | 1729 encoding = "utf-8" |
1709 cmd_std_out, cmd_std_err = await p.communicate(item.encode(encoding)) | 1730 cmd_std_out, cmd_std_err = await p.communicate(item.encode(encoding)) |
1710 ret = p.returncode | 1731 ret = p.returncode |
1711 if ret != 0: | 1732 if ret != 0: |
1712 self.disp(f"The command returned a non zero status while parsing the " | 1733 self.disp( |
1713 f"following item:\n\n{item}", error=True) | 1734 f"The command returned a non zero status while parsing the " |
1735 f"following item:\n\n{item}", | |
1736 error=True, | |
1737 ) | |
1714 if self.args.ignore_errors: | 1738 if self.args.ignore_errors: |
1715 continue | 1739 continue |
1716 else: | 1740 else: |
1717 self.host.quit(C.EXIT_CMD_ERROR) | 1741 self.host.quit(C.EXIT_CMD_ERROR) |
1718 if cmd_std_err is not None: | 1742 if cmd_std_err is not None: |
1719 cmd_std_err = cmd_std_err.decode(encoding, errors='ignore') | 1743 cmd_std_err = cmd_std_err.decode(encoding, errors="ignore") |
1720 self.disp(cmd_std_err, error=True) | 1744 self.disp(cmd_std_err, error=True) |
1721 cmd_std_out = cmd_std_out.decode(encoding).strip() | 1745 cmd_std_out = cmd_std_out.decode(encoding).strip() |
1722 if cmd_std_out == "DELETE": | 1746 if cmd_std_out == "DELETE": |
1723 item_elt, __ = xml_tools.etreeParse(self, item) | 1747 item_elt, __ = xml_tools.etreeParse(self, item) |
1724 item_id = item_elt.get('id') | 1748 item_id = item_elt.get("id") |
1725 self.disp(_(f"Deleting item {item_id}")) | 1749 self.disp(_("Deleting item {item_id}").format(item_id=item_id)) |
1726 if self.args.apply: | 1750 if self.args.apply: |
1727 try: | 1751 try: |
1728 await self.host.bridge.psItemRetract( | 1752 await self.host.bridge.psItemRetract( |
1729 self.args.service, | 1753 self.args.service, |
1730 self.args.node, | 1754 self.args.node, |
1731 item_id, | 1755 item_id, |
1732 False, | 1756 False, |
1733 self.profile, | 1757 self.profile, |
1734 ) | 1758 ) |
1735 except Exception as e: | 1759 except Exception as e: |
1736 self.disp( | 1760 self.disp(f"can't delete item {item_id}: {e}", error=True) |
1737 f"can't delete item {item_id}: {e}", error=True | |
1738 ) | |
1739 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1761 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
1740 continue | 1762 continue |
1741 elif cmd_std_out == "SKIP": | 1763 elif cmd_std_out == "SKIP": |
1742 item_elt, __ = xml_tools.etreeParse(self, item) | 1764 item_elt, __ = xml_tools.etreeParse(self, item) |
1743 item_id = item_elt.get('id') | 1765 item_id = item_elt.get("id") |
1744 self.disp(_("Skipping item {item_id}").format(item_id=item_id)) | 1766 self.disp(_("Skipping item {item_id}").format(item_id=item_id)) |
1745 continue | 1767 continue |
1746 element, etree = xml_tools.etreeParse(self, cmd_std_out) | 1768 element, etree = xml_tools.etreeParse(self, cmd_std_out) |
1747 | 1769 |
1748 # at this point command has been run and we have a etree.Element object | 1770 # at this point command has been run and we have a etree.Element object |
1749 if element.tag not in ("item", "{http://jabber.org/protocol/pubsub}item"): | 1771 if element.tag not in ("item", "{http://jabber.org/protocol/pubsub}item"): |
1750 self.disp("your script must return a whole item, this is not:\n{xml}" | 1772 self.disp( |
1751 .format(xml=etree.tostring(element, encoding="unicode")), error=True) | 1773 "your script must return a whole item, this is not:\n{xml}".format( |
1774 xml=etree.tostring(element, encoding="unicode") | |
1775 ), | |
1776 error=True, | |
1777 ) | |
1752 self.host.quit(C.EXIT_DATA_ERROR) | 1778 self.host.quit(C.EXIT_DATA_ERROR) |
1753 | 1779 |
1754 if not self.args.apply: | 1780 if not self.args.apply: |
1755 # we have a dry run, we just display filtered items | 1781 # we have a dry run, we just display filtered items |
1756 serialised = etree.tostring(element, encoding='unicode', | 1782 serialised = etree.tostring( |
1757 pretty_print=True) | 1783 element, encoding="unicode", pretty_print=True |
1784 ) | |
1758 self.disp(serialised) | 1785 self.disp(serialised) |
1759 else: | 1786 else: |
1760 new_items.append(etree.tostring(element, encoding="unicode")) | 1787 new_items.append(etree.tostring(element, encoding="unicode")) |
1761 | 1788 |
1762 if not self.args.apply: | 1789 if not self.args.apply: |
1786 | 1813 |
1787 async def start(self): | 1814 async def start(self): |
1788 if self.args.all and self.args.order_by != C.ORDER_BY_CREATION: | 1815 if self.args.all and self.args.order_by != C.ORDER_BY_CREATION: |
1789 self.check_duplicates = True | 1816 self.check_duplicates = True |
1790 self.items_ids = [] | 1817 self.items_ids = [] |
1791 self.disp(A.color( | 1818 self.disp( |
1792 A.FG_RED, A.BOLD, | 1819 A.color( |
1793 '/!\\ "--all" should be used with "--order-by creation" /!\\\n', | 1820 A.FG_RED, |
1794 A.RESET, | 1821 A.BOLD, |
1795 "We'll update items, so order may change during transformation,\n" | 1822 '/!\\ "--all" should be used with "--order-by creation" /!\\\n', |
1796 "we'll try to mitigate that by stopping on first duplicate,\n" | 1823 A.RESET, |
1797 "but this method is not safe, and some items may be missed.\n---\n")) | 1824 "We'll update items, so order may change during transformation,\n" |
1825 "we'll try to mitigate that by stopping on first duplicate,\n" | |
1826 "but this method is not safe, and some items may be missed.\n---\n", | |
1827 ) | |
1828 ) | |
1798 else: | 1829 else: |
1799 self.check_duplicates = False | 1830 self.check_duplicates = False |
1800 | 1831 |
1801 try: | 1832 try: |
1802 ps_result = data_format.deserialise( | 1833 ps_result = data_format.deserialise( |
1853 | 1884 |
1854 async def start(self): | 1885 async def start(self): |
1855 if not self.args.service: | 1886 if not self.args.service: |
1856 try: | 1887 try: |
1857 jid_ = await self.host.bridge.asyncGetParamA( | 1888 jid_ = await self.host.bridge.asyncGetParamA( |
1858 "JabberID", | 1889 "JabberID", "Connection", profile_key=self.args.profile |
1859 "Connection", | |
1860 profile_key=self.args.profile | |
1861 ) | 1890 ) |
1862 except Exception as e: | 1891 except Exception as e: |
1863 self.disp(f"can't retrieve jid: {e}", error=True) | 1892 self.disp(f"can't retrieve jid: {e}", error=True) |
1864 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1893 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
1865 else: | 1894 else: |
1966 ) | 1995 ) |
1967 except Exception as e: | 1996 except Exception as e: |
1968 self.disp(f"can't delete hook: {e}", error=True) | 1997 self.disp(f"can't delete hook: {e}", error=True) |
1969 self.host.quit(C.EXIT_BRIDGE_ERRBACK) | 1998 self.host.quit(C.EXIT_BRIDGE_ERRBACK) |
1970 else: | 1999 else: |
1971 self.disp(_(f"{nb_deleted} hook(s) have been deleted")) | 2000 self.disp( |
2001 _("{nb_deleted} hook(s) have been deleted").format(nb_deleted=nb_deleted) | |
2002 ) | |
1972 self.host.quit() | 2003 self.host.quit() |
1973 | 2004 |
1974 | 2005 |
1975 class HookList(base.CommandBase): | 2006 class HookList(base.CommandBase): |
1976 def __init__(self, host): | 2007 def __init__(self, host): |