[TIC-Core] UI element HF and QT implemented. GBS support of category
[archive/20170607/tools/tic-core.git] / tic / parser / view_parser.py
index 586307d..bb6f06d 100644 (file)
+#!/usr/bin/python
+# Copyright (c) 2016 Samsung Electronics Co., Ltd
+#
+# Licensed under the Flora License, Version 1.1 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://floralicense.org/license/
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Contributors:
+# - S-Core Co., Ltd
+
 import logging
+import requests
+import re
 from operator import itemgetter
+from tic.utils.rpmmisc import meetRequireVersion
 
 
 def make_view_data(pkg_group):
     logger = logging.getLogger(__name__)
     
+    def _select_provide_rpm(capability, require):
+        provide_list = []
+        if require.get('ver') is not None:
+            for provide in capability:
+                ver_data = provide['data']
+                if not ver_data.get('ver'):
+                    ver_data = pkg_dict.get(provide['name']).get('version')
+                if meetRequireVersion(require, ver_data):
+                    provide_list.append(provide)
+        else:
+            provide_list = capability
+            
+        result = []
+        for provide in provide_list:
+            result.append(pkg_dict[provide['name']])
+            
+        return result
+    
     def set_meta_require(meta_info):
         meta_nodes = meta_info.get('nodes')
+        children = set()
         for child_meta in meta_nodes:
-            refer_count[child_meta['id']] += 1
             set_meta_require(child_meta)
-            
-        req_list = pkg_dict[meta_info['text']].get('requires')
-        if req_list is not None:
-            for req in req_list:
-                if provides.get(req['name']):
-                    provide_info = provides[req['name']][0]
-                    pkg_name = provide_info['name']
-                    if 'meta' not in pkg_dict[pkg_name]:
-                        child_pkg = pkg_dict[pkg_name]
-                        meta_nodes.append(make_node(child_pkg))
-                        refer_count[child_pkg['id']] += 1
+            children.add(child_meta['metaname'])
+        
+        duplicate = set()
+        pkg_info = pkg_dict[meta_info['metaname']]
+        for dep_tag in ['requires', 'recommends', 'suggests']:
+            if pkg_info.get(dep_tag):
+                for req in pkg_info.get(dep_tag):
+                    targets = []
+                    if req['name'] in provides:
+                        targets = _select_provide_rpm(provides[req['name']], req)
+                    elif req['name'] in files:
+                        for fname in files[req['name']]:
+                            targets.append(pkg_dict.get(fname))
+                    elif req['name'] in pkg_dict:
+                        targets.append(pkg_dict.get(req['name']))
                     else:
-                        # The meta-pkg of the other group are excluded.
                         # the dependent package does not exist.
                         pass
-                
-    def make_node(pkg_info):
-        return dict(id=pkg_info['id'], text=pkg_info['name'], nodes=[])
-            
+                        
+                    for pkg in targets:
+                        # The meta-pkg of the other group are excluded.
+                        if pkg['name'] not in duplicate:
+                            refer_count[pkg['id']] += 1
+                            duplicate.add(pkg['name'])
+
+                            if pkg.get('meta'):
+                                if not pkg['name'] in children:
+                                    meta_nodes.append(make_linked_meta_node(pkg['name'], pkg['summary'], meta_info['category']))
+                            else:
+                                meta_nodes.append(make_node(pkg, meta_info.get('category')))
+        # Added 'zz' to non meta-package because they are to be listed last
+        meta_nodes = sorted(meta_nodes, key = lambda k: 'aa'+k['metaname'] if 'metaname' in k else 'zz'+k['text'])
+        meta_info['nodes'] = meta_nodes
+
+        if meta_info['metaname'] =='building-blocks-sub2-Preset_iot-examples-3_RPI3_headless_devboard':
+            print(pkg_info)
+    def make_node(pkg_info, category=None):
+        n = dict(text=pkg_info['name'], nodes=[])
+        if category: n['category'] = category
+        return n
+    def make_meta_node(pkgname, viewtext):
+        return dict(text=viewtext, metaname=pkgname, nodes=[])
+    def make_linked_meta_node(pkgname, viewtext, cat):
+        return dict(text='&nbsp;&nbsp;<i>'+viewtext+'</i>', metaname=pkgname, nodes=[], category=cat, tooltip="This is a link of a building block.")
+    def is_blank_ui_meta_node(pkgname):
+        return (pkgname[-8:-2] == '__UI__')
+    def handle_ui_meta_node(tag, node):
+        node['selectable'] = False
+        node['hideCheckbox'] = True
+        if tag == 'BR' or tag == 'br':
+            node['text'] = ''
+        elif tag == 'HR' or tag == 'hr':
+            node['text'] = '<hr style="margin-bottom: 0px; margin-top: 0px; border-style: inset; border-width: 3px" />'
+        elif tag == 'SD' or tag == 'sd':
+            node['text'] = ''
+            node['backColor'] = '#101010'
+        elif tag == 'SM' or tag == 'sm':
+            # Keep the summary text
+            node['text'] = node['text']
+        elif tag == 'HT' or tag == 'ht':
+            # Keep the summary (TODO: verify the usage of HTML tags.)
+            node['text'] = node['text'] # Do we need conversion?
+        elif tag == 'HF' or tag == 'hf':
+            node['text'] = '<p style="height:0px; margin-bottom:-10px"></p>'
+        elif tag == 'QT' or tag == 'qt':
+            node['text'] = '<p style="height:0px; margin-bottom:-16px"></p>'
+        else:
+            node['text'] = ''
+        return node
+    def handle_description(node):
+        if 'metaname' in node:
+            name = node['metaname']
+            pkg_info = pkg_dict[name]
+            desc = pkg_info.get('description')
+            if desc[0:10] == '__KS_URL__':
+                logger.info("Processing "+name+" for its description: "+pkg_info.get('description'))
+                # Extract URL from __KS_URL__
+                ksURL = desc[11:].splitlines()[0].strip()
+                # Omit the first line with __KS_URL__ from showing.
+                pkg_info['description'] = desc[len(desc.splitlines(True)[0]):]
+
+                # Search for filename if directory is given
+                # e.g., Convert http://a.com/a/ to https://a.com/a/blahblah.ks
+                # Works for file-indexing html
+                if ksURL[-3:].lower() != ".ks":
+                    m = None
+                    error = 0
+                    if ksURL[-1:] != "/":
+                        ksURL += "/"
+                    r = requests.get(ksURL)
+                    if r.status_code == requests.codes.ok:
+                        m = re.search('>([^<]*\\.ks)\\s*<', r.text)
+                    else:
+                        error = 1
+                    if error == 0 and not m:
+                        m = re.search('"([^"]*\\.ks)\\s*"', r.text)
+                        if not m:
+                            m = re.search("'([^']*\\.ks)\\s*'", r.text)
+                            if not m:
+                                error = 1
+                    if error == 1:
+                        node['icon'] = 'glyphicon glyphicon-remove-sign'
+                        node['tooltip'] = 'Cannot find image base from' + ksURL
+                        return node
+                    ksURL += m.group(0)
+                node['tooltip'] = 'Image base from '+ksURL
+                node['icon'] = 'glyphicon glyphicon-list-alt'
+                node['ks'] = ksURL
+            elif desc[0:10] == '__EXPAND__':
+                # Omit the first line with __EXPAND__ from showing.
+                pkg_info['description'] = desc[len(desc.splitlines(True)[0]):]
+                option = desc.splitlines()[0][10:].strip(': \t')
+                if len(option) == 0:
+                    node['expandcondition'] = 'all'
+                else:
+                    node['expandcondition'] = option
+        return node
+
     # view_data for tree view on web-ui
     view_data = []
     # temporary dictionary for referencing meta
@@ -39,39 +177,85 @@ def make_view_data(pkg_group):
       
     pkg_dict = pkg_group['pkg_dict']
     provides = pkg_group['provides']
+    files = pkg_group['files']
     refer_count = [0] * len(pkg_dict)
     
-    # sort by pkg_name ([0]:name, [1]:root, [2]:sub1)
+    # sort meta-pkg by pkt_name in ascending order
     meta_info = pkg_group.get('meta_info')
     meta_info['root'] = sorted(meta_info['root'], key=itemgetter(0))
     meta_info['sub1'] = sorted(meta_info['sub1'], key=itemgetter(0))
     meta_info['sub2'] = sorted(meta_info['sub2'], key=itemgetter(0))
     
+    # make category rpms
+    category_dict = {}
+    if meta_info.get('category'):
+        for category in meta_info['category']:
+            c_rpm = pkg_dict[category[0]]
+            if hasattr(c_rpm.get('suggests'), '__iter__'):
+                for suggest in c_rpm.get('suggests'):
+                    category_dict[suggest['name']] = category[1]
+            else:
+                logger.info(c_rpm.get('suggests'))
+                logger.info(c_rpm.get('name'))
+
+    
     # make tree of meta
     for root in meta_info['root']:
-        root_node = make_node(pkg_dict[root[0]])
+        root_node = make_meta_node(root[0], root[1])
         view_ref[root[0]] = root_node
+        if root[0] in category_dict:
+            root_node['category'] = category_dict[root[0]]
+        else:
+            # Backup routine for GBS, which does not seem to publish suggest info correctly.
+            # TODO: This routine has hardcoded category names, which should be improved.
+            m = re.search('(?<=root-)[a-zA-Z]*', root[0])
+            if m:
+                cat = m.group(0)
+                if cat == 'domain':
+                    cat = 'domains'
+                if cat == 'feature':
+                    cat = 'epicfeatures'
+                root_node['category'] = cat
+                logger.info("Fallback for "+cat+" for "+root[0])
+        if is_blank_ui_meta_node(root[0]):
+            name = root[0]
+            sub1_node = handle_ui_meta_node(name[-2:], root_node)
+        root_node = handle_description(root_node)
         view_data.append(root_node)
         
     for sub1 in meta_info['sub1']:
-        sub1_node = make_node(pkg_dict[sub1[0]])
+        sub1_node = make_meta_node(sub1[0], sub1[2])
         view_ref[sub1[0]] = sub1_node
+        if is_blank_ui_meta_node(sub1[0]):
+            name = sub1[0]
+            sub1_node = handle_ui_meta_node(name[-2:], sub1_node)
+        sub1_node = handle_description(sub1_node)
         # search root
         if sub1[1] in view_ref:
             # add to root node
+            if 'category' in view_ref[sub1[1]] and view_ref[sub1[1]]['category']:
+                sub1_node['category'] = view_ref[sub1[1]]['category']
             view_ref[sub1[1]]['nodes'].append(sub1_node)
         else:
             # If root-meta does not exist, sub1 is added to top-level
             view_data.append(sub1_node)
             
     for sub2 in meta_info['sub2']:
-        sub2_node = make_node(pkg_dict[sub2[0]])
+        sub2_node = make_meta_node(sub2[0], sub2[3])
         view_ref[sub2[0]] = sub2_node
+        if is_blank_ui_meta_node(sub2[0]):
+            name = sub2[0]
+            sub1_node = handle_ui_meta_node(name[-2:], sub2_node)
+        sub2_node = handle_description(sub2_node)
         # search sub1
         if sub2[2] in view_ref:
+            if 'category' in view_ref[sub2[2]] and view_ref[sub2[2]]['category']:
+                sub2_node['category'] = view_ref[sub2[2]]['category']
             view_ref[sub2[2]]['nodes'].append(sub2_node)
         # search root    
         elif sub2[1] in view_ref: 
+            if view_ref[sub2[1]]['category']:
+                sub2_node['category'] = view_ref[sub2[1]]['category']
             # If sub1-meta does not exist, sub2 is added to child of root-meta
             view_ref[sub2[1]]['nodes'].append(sub2_node)
         else:
@@ -80,21 +264,18 @@ def make_view_data(pkg_group):
     
     # configure meta dependency tree (requires)
     for meta_pkg in view_data:
-        refer_count[meta_pkg['id']] += 1
         set_meta_require(meta_pkg)
-    
+        
     #The remaining rpms are grouped into a MISC tree
     misc_info = {}
-    misc_info['text'] = 'MISC'
+    misc_info['text'] = 'Advanced (individual packages)'
     misc_info['nodes'] = []
     for k, v in pkg_dict.iteritems():
-        # Pkg is not referenced from Meta-pkg
-        if refer_count[v['id']] == 0:
+        # Add ALL non-block packages
+        if v['name'][0:15] != 'building-blocks':
             misc_info['nodes'].append(make_node(v))
-            
-    logger.info('meta: %d, misc: %d', len(view_ref), len(misc_info['nodes']))
-    
+    misc_info['nodes'] = sorted(misc_info['nodes'], key = lambda k: k['metaname'] if 'metaname' in k else k['text'])
+
     view_data.append(misc_info)
-    
+    logger.info('meta: %d, misc: %d', len(view_ref), len(misc_info['nodes']))
     return view_data
-