# HG changeset patch # User Goffi # Date 1504676350 -7200 # Node ID 3c0a3fae18622febd3958ab0782c9099a1c119f0 # Parent 388226e9c3ffe675527742807e6bea6c263581ee jp (pubsub/node): added schema (set/edit/get) commands to manipulate PubSub node schema diff -r 388226e9c3ff -r 3c0a3fae1862 frontends/src/jp/cmd_pubsub.py --- a/frontends/src/jp/cmd_pubsub.py Wed Sep 06 07:38:39 2017 +0200 +++ b/frontends/src/jp/cmd_pubsub.py Wed Sep 06 07:39:10 2017 +0200 @@ -37,6 +37,7 @@ __commands__ = ["Pubsub"] PUBSUB_TMP_DIR = u"pubsub" +PUBSUB_SCHEMA_TMP_DIR = PUBSUB_TMP_DIR + "_schema" ALLOWED_SUBSCRIPTIONS_OWNER = ('subscribed', 'pending', 'none') # TODO: need to split this class in several modules, plugin should handle subcommands @@ -362,8 +363,119 @@ super(NodeSubscriptions, self).__init__(host, 'subscriptions', use_profile=False, help=_(u'get or modify node subscriptions')) +class NodeSchemaSet(base.CommandBase): + + def __init__(self, host): + base.CommandBase.__init__(self, host, 'set', use_pubsub_node_req=True, use_verbose=True, help=_(u'set/replace a schema')) + self.need_loop = True + + def add_parser_options(self): + self.parser.add_argument('schema', help=_(u"schema to set (must be XML)")) + + def psSchemaSetCb(self): + self.disp(_(u'schema has been set'), 1) + self.host.quit() + + def start(self): + self.host.bridge.psSchemaSet( + self.args.service, + self.args.node, + self.args.schema, + self.profile, + callback=self.psSchemaSetCb, + errback=partial(self.errback, + msg=_(u"can't set schema: {}"), + exit_code=C.EXIT_BRIDGE_ERRBACK)) + + +class NodeSchemaEdit(base.CommandBase, common.BaseEdit): + use_items=False + + def __init__(self, host): + base.CommandBase.__init__(self, host, 'edit', use_pubsub_node_req=True, use_verbose=True, help=_(u'edit a schema')) + common.BaseEdit.__init__(self, self.host, PUBSUB_SCHEMA_TMP_DIR) + self.need_loop=True + + def add_parser_options(self): + common.BaseEdit.add_parser_options(self) + + def psSchemaSetCb(self): + self.disp(_(u'schema has been set'), 1) + self.host.quit() + + def publish(self, schema): + self.host.bridge.psSchemaSet( + self.args.service, + self.args.node, + schema, + self.profile, + callback=self.psSchemaSetCb, + errback=partial(self.errback, + msg=_(u"can't set schema: {}"), + exit_code=C.EXIT_BRIDGE_ERRBACK)) + + def psSchemaGetCb(self, schema): + try: + from lxml import etree + except ImportError: + self.disp(u"lxml module must be installed to use edit, please install it with \"pip install lxml\"", error=True) + self.host.quit(1) + parser = etree.XMLParser(remove_blank_text=True) + schema_elt = etree.fromstring(schema, parser) + content_file_obj, content_file_path = self.getTmpFile() + content_file_obj.write(etree.tostring(schema_elt, encoding="utf-8", pretty_print=True)) + content_file_obj.seek(0) + self.runEditor("pubsub_schema_editor_args", content_file_path, content_file_obj) + + def start(self): + common.checkURI(self.args) + self.host.bridge.psSchemaGet( + self.args.service, + self.args.node, + self.profile, + callback=self.psSchemaGetCb, + errback=partial(self.errback, + msg=_(u"can't edit schema: {}"), + exit_code=C.EXIT_BRIDGE_ERRBACK)) + + +class NodeSchemaGet(base.CommandBase): + + def __init__(self, host): + base.CommandBase.__init__(self, host, 'get', use_output=C.OUTPUT_XML, use_pubsub_node_req=True, use_verbose=True, help=_(u'get schema')) + self.need_loop=True + + def add_parser_options(self): + pass + + def psSchemaGetCb(self, schema): + if not schema: + self.disp(_(u'no schema found'), 1) + self.host.quit(1) + self.output(schema) + self.host.quit() + + def start(self): + common.checkURI(self.args) + self.host.bridge.psSchemaGet( + self.args.service, + self.args.node, + self.profile, + callback=self.psSchemaGetCb, + errback=partial(self.errback, + msg=_(u"can't get schema: {}"), + exit_code=C.EXIT_BRIDGE_ERRBACK)) + + +class NodeSchema(base.CommandBase): + subcommands = (NodeSchemaSet, NodeSchemaEdit, NodeSchemaGet) + + def __init__(self, host): + super(NodeSchema, self).__init__(host, 'schema', use_profile=False, help=_(u"data schema manipulation")) + + class Node(base.CommandBase): - subcommands = (NodeInfo, NodeCreate, NodeDelete, NodeSet, NodeAffiliations, NodeSubscriptions) + subcommands = (NodeInfo, NodeCreate, NodeDelete, NodeSet, NodeAffiliations, NodeSubscriptions, NodeSchema) def __init__(self, host): super(Node, self).__init__(host, 'node', use_profile=False, help=_('node handling')) @@ -447,7 +559,7 @@ class Edit(base.CommandBase, common.BaseEdit): def __init__(self, host): - base.CommandBase.__init__(self, host, 'edit', use_verbose=True, use_pubsub=True, help=_(u'edit an existing or new pubsub item')) + base.CommandBase.__init__(self, host, 'edit', use_verbose=True, use_pubsub_node_req=True, help=_(u'edit an existing or new pubsub item')) common.BaseEdit.__init__(self, self.host, PUBSUB_TMP_DIR) def add_parser_options(self): @@ -980,7 +1092,7 @@ subcommands = (HookCreate, HookDelete, HookList) def __init__(self, host): - super(Hook, self).__init__(host, 'hook', use_profile=False, help=_('trigger action on Pubsub notifications')) + super(Hook, self).__init__(host, 'hook', use_profile=False, use_verbose=True, help=_('trigger action on Pubsub notifications')) class Pubsub(base.CommandBase): diff -r 388226e9c3ff -r 3c0a3fae1862 frontends/src/jp/common.py --- a/frontends/src/jp/common.py Wed Sep 06 07:38:39 2017 +0200 +++ b/frontends/src/jp/common.py Wed Sep 06 07:39:10 2017 +0200 @@ -136,6 +136,8 @@ This class allows to edit file for PubSub or something else. It works with temporary files in SàT local_dir, in a "cat_dir" subdir """ + # use_items(bool): True if items are used, will then add item related options + use_items=True def __init__(self, host, cat_dir, use_metadata=False): """ @@ -152,9 +154,10 @@ self.use_metadata = use_metadata def add_parser_options(self): - group = self.parser.add_mutually_exclusive_group() - group.add_argument("--force-item", action='store_true', help=_(u"don't use magic and take item argument as an actual item")) - group.add_argument("--last-item", action='store_true', help=_(u"take last item instead of creating a new one if no item id is found")) + if self.use_items: + group = self.parser.add_mutually_exclusive_group() + group.add_argument("--force-item", action='store_true', help=_(u"don't use magic and take item argument as an actual item")) + group.add_argument("--last-item", action='store_true', help=_(u"take last item instead of creating a new one if no item id is found")) def secureUnlink(self, path): """Unlink given path after keeping it for a while @@ -311,12 +314,13 @@ # if metadata is needed, publish will be called with it last argument raise NotImplementedError - def getTmpFile(self, suff): + def getTmpFile(self): """Create a temporary file @param suff (str): suffix to use for the filename @return (tuple(file, str)): opened (w+b) file object and file path """ + suff = '.' + self.getTmpSuff() cat_dir_str = self.cat_dir_str tmp_dir = getTmpDir(self.sat_conf, self.cat_dir_str, self.profile.encode('utf-8')) if not os.path.exists(tmp_dir): @@ -443,8 +447,7 @@ if not force_item and command in ('new', 'last', 'edit'): # we need a temporary file - tmp_suff = '.' + self.getTmpSuff() - content_file_obj, content_file_path = self.getTmpFile(tmp_suff) + content_file_obj, content_file_path = self.getTmpFile() if command == 'new': self.disp(u'Editing a new item', 2) if self.use_metadata: @@ -475,8 +478,7 @@ content_file_obj = open(content_file_path, 'r+b') else: # last chance, it should be an item - tmp_suff = '.' + self.getTmpSuff() - content_file_obj, content_file_path = self.getTmpFile(tmp_suff) + content_file_obj, content_file_path = self.getTmpFile() pubsub_item = self.args.item try: