Blob Blame History Raw
From 5386802ebc96ef0c2bc4a3bfa260ee83a6d7fe5f Mon Sep 17 00:00:00 2001
From: David Kupka <dkupka@redhat.com>
Date: Tue, 2 Aug 2016 08:16:30 +0200
Subject: [PATCH] schema: Generate bits for help load them on request

Store name, summary, topic_topic and exclude in single entry in cache
for all commands. These data are needed for help and storing and
loading them together allows fast help response.

https://fedorahosted.org/freeipa/ticket/6048

Reviewed-By: Jan Cholasta <jcholast@redhat.com>
---
 ipaclient/remote_plugins/schema.py | 54 +++++++++++++++++++++++++++++---------
 1 file changed, 42 insertions(+), 12 deletions(-)

diff --git a/ipaclient/remote_plugins/schema.py b/ipaclient/remote_plugins/schema.py
index d7c018e3de1cc79ffc086e3576542ce993ebc87a..5264d4cc177ba457c517f93f203e0baca7b0ac01 100644
--- a/ipaclient/remote_plugins/schema.py
+++ b/ipaclient/remote_plugins/schema.py
@@ -23,7 +23,7 @@ from ipapython.dn import DN
 from ipapython.dnsutil import DNSName
 from ipapython.ipa_log_manager import log_mgr
 
-FORMAT = '0'
+FORMAT = '1'
 
 if six.PY3:
     unicode = str
@@ -113,9 +113,11 @@ class _SchemaPlugin(object):
         if self._class is not None:
             return self._class.summary
         else:
-            if self.doc is not None:
-                return self.doc.split('\n\n', 1)[0].strip()
-            else:
+            self._schema.load_help()
+            schema = self._schema[self.schema_key][self.full_name]
+            try:
+                return schema['summary']
+            except KeyError:
                 return u'<%s>' % self.full_name
 
     def _create_default_from(self, api, name, keys):
@@ -241,6 +243,7 @@ class _SchemaCommandPlugin(_SchemaPlugin):
         if self._class is not None:
             return self._class.topic
         else:
+            self._schema.load_help()
             schema = self._schema[self.schema_key][self.full_name]
             try:
                 return str(schema['topic_topic']).partition('/')[0]
@@ -252,6 +255,7 @@ class _SchemaCommandPlugin(_SchemaPlugin):
         if self._class is not None:
             return self._class.NO_CLI
         else:
+            self._schema.load_help()
             schema = self._schema[self.schema_key][self.full_name]
             return 'cli' in schema.get('exclude', [])
 
@@ -432,7 +436,6 @@ class Schema(object):
 
     """
     namespaces = {'classes', 'commands', 'topics'}
-    schema_info_path = 'schema'
     _DIR = os.path.join(USER_CACHE_PATH, 'ipa', 'schema')
 
     def __init__(self, api, server_info, client):
@@ -488,8 +491,7 @@ class Schema(object):
         if fmt != FORMAT:
             raise RuntimeError('invalid format')
 
-        schema_info = json.loads(schema.read(self.schema_info_path))
-        return schema_info['fingerprint']
+        return json.loads(schema.read('fingerprint'))
 
     def _fetch(self, client):
         if not client.isconnected():
@@ -522,6 +524,7 @@ class Schema(object):
         else:
             fp = schema['fingerprint']
             ttl = schema.pop('ttl', 0)
+            schema.pop('version', None)
 
             for key, value in schema.items():
                 if key in self.namespaces:
@@ -534,8 +537,6 @@ class Schema(object):
     def _read_schema(self):
         with self._open_schema(self._fingerprint, 'r') as schema:
             self._dict['fingerprint'] = self._get_schema_fingerprint(schema)
-            schema_info = json.loads(schema.read(self.schema_info_path))
-            self._dict['version'] = schema_info['version']
 
             for name in schema.namelist():
                 ns, _slash, key = name.partition('/')
@@ -548,6 +549,27 @@ class Schema(object):
         except KeyError:
             return self._dict[key]
 
+    def _generate_help(self, schema):
+        halp = {}
+
+        for namespace in ('commands', 'topics'):
+            halp[namespace] = {}
+
+            for member_schema in schema[namespace].values():
+                member_full_name = member_schema['full_name']
+
+                topic = halp[namespace].setdefault(member_full_name, {})
+                topic['name'] = member_schema['name']
+                if 'doc' in member_schema:
+                    topic['summary'] = (
+                        member_schema['doc'].split('\n\n', 1)[0].strip())
+                if 'topic_topic' in member_schema:
+                    topic['topic_topic'] = member_schema['topic_topic']
+                if 'exclude' in member_schema:
+                    topic['exclude'] = member_schema['exclude']
+
+        return halp
+
     def _write_schema(self):
         try:
             os.makedirs(self._DIR)
@@ -557,7 +579,6 @@ class Schema(object):
                 return
 
         with self._open_schema(self._fingerprint, 'w') as schema:
-            schema_info = {}
             for key, value in self._dict.items():
                 if key in self.namespaces:
                     ns = value
@@ -565,9 +586,10 @@ class Schema(object):
                         path = '{}/{}'.format(key, member)
                         schema.writestr(path, json.dumps(ns[member]))
                 else:
-                    schema_info[key] = value
+                    schema.writestr(key, json.dumps(value))
 
-            schema.writestr(self.schema_info_path, json.dumps(schema_info))
+            schema.writestr('_help',
+                            json.dumps(self._generate_help(self._dict)))
 
     def _read(self, path):
         with self._open_schema(self._fingerprint, 'r') as zf:
@@ -587,6 +609,14 @@ class Schema(object):
     def iter_namespace(self, namespace):
         return iter(self._dict[namespace])
 
+    def load_help(self):
+        if not self._help:
+            self._help = self._read('_help')
+
+            for ns in self._help:
+                for member in self._help[ns]:
+                    self._dict[ns][member].update(self._help[ns][member])
+
 
 def get_package(api, client):
     try:
-- 
2.7.4