[TIC-Core] Allow to express UI elements within package list with UI meta blocks
[archive/20170607/tools/tic-core.git] / tic / parser / view_parser.py
1 import logging
2 from operator import itemgetter
3 from tic.utils.rpmmisc import meetRequireVersion
4
5
6 def make_view_data(pkg_group):
7     logger = logging.getLogger(__name__)
8     
9     def _select_provide_rpm(capability, require):
10         provide_list = []
11         if require.get('ver') is not None:
12             for provide in capability:
13                 ver_data = provide['data']
14                 if not ver_data.get('ver'):
15                     ver_data = pkg_dict.get(provide['name']).get('version')
16                 if meetRequireVersion(require, ver_data):
17                     provide_list.append(provide)
18         else:
19             provide_list = capability
20             
21         result = []
22         for provide in provide_list:
23             result.append(pkg_dict[provide['name']])
24             
25         return result
26     
27     def set_meta_require(meta_info):
28         meta_nodes = meta_info.get('nodes')
29         for child_meta in meta_nodes:
30             set_meta_require(child_meta)
31         
32         duplicate = set()
33         pkg_info = pkg_dict[meta_info['metaname']]
34         for dep_tag in ['requires', 'recommends', 'suggests']:
35             if pkg_info.get(dep_tag):
36                 for req in pkg_info.get(dep_tag):
37                     targets = []
38                     if req['name'] in provides:
39                         targets = _select_provide_rpm(provides[req['name']], req)
40                     elif req['name'] in files:
41                         for fname in files[req['name']]:
42                             targets.append(pkg_dict.get(fname))
43                     elif req['name'] in pkg_dict:
44                         targets.append(pkg_dict.get(req['name']))
45                     else:
46                         # the dependent package does not exist.
47                         pass
48                         
49                     for pkg in targets:
50                         # The meta-pkg of the other group are excluded.
51                         if not pkg.get('meta') and pkg['name'] not in duplicate:
52                             refer_count[pkg['id']] += 1
53                             duplicate.add(pkg['name'])
54                             meta_nodes.append(make_node(pkg, meta_info.get('category')))
55         # Added 'zz' to non meta-package because they are to be listed last
56         meta_nodes = sorted(meta_nodes, key = lambda k: k['metaname'] if 'metaname' in k else 'zz'+k['text'])
57         meta_info['nodes'] = meta_nodes
58     def make_node(pkg_info, category=None):
59         n = dict(text=pkg_info['name'], nodes=[])
60         if category: n['category'] = category
61         return n
62     def make_meta_node(pkgname, viewtext):
63         return dict(text=viewtext, metaname=pkgname, nodes=[])
64     def is_blank_ui_meta_node(pkgname):
65         return (pkgname[-8:-2] == '__UI__')
66     def handle_ui_meta_node(tag, node):
67         node['selectable'] = False
68         node['hideCheckbox'] = True
69         if tag == 'BR' or tag == 'br':
70             node['text'] = ''
71         elif tag == 'HR' or tag == 'hr':
72             node['text'] = '<hr style="margin-bottom: 0px; margin-top: 0px; border-style: inset; border-width: 3px" />'
73         elif tag == 'SD' or tag == 'sd':
74             node['text'] = ''
75             node['backColor'] = '#101010'
76         elif tag == 'SM' or tag == 'sm':
77             # Keep the summary text
78             node['text'] = node['text']
79         elif tag == 'HT' or tag == 'ht':
80             # Keep the summary (TODO: verify the usage of HTML tags.)
81             node['text'] = node['text'] # Do we need conversion?
82         else:
83             node['text'] = ''
84         return node
85
86     # view_data for tree view on web-ui
87     view_data = []
88     # temporary dictionary for referencing meta
89     view_ref = {}
90     
91     if not pkg_group:
92         return view_data
93       
94     pkg_dict = pkg_group['pkg_dict']
95     provides = pkg_group['provides']
96     files = pkg_group['files']
97     refer_count = [0] * len(pkg_dict)
98     
99     # sort meta-pkg by pkt_name in ascending order
100     meta_info = pkg_group.get('meta_info')
101     meta_info['root'] = sorted(meta_info['root'], key=itemgetter(0))
102     meta_info['sub1'] = sorted(meta_info['sub1'], key=itemgetter(0))
103     meta_info['sub2'] = sorted(meta_info['sub2'], key=itemgetter(0))
104     
105     # make category rpms
106     category_dict = {}
107     if meta_info.get('category'):
108         for category in meta_info['category']:
109             c_rpm = pkg_dict[category[0]]
110             if hasattr(c_rpm.get('suggests'), '__iter__'):
111                 for suggest in c_rpm.get('suggests'):
112                     category_dict[suggest['name']] = category[1]
113             else:
114                 logger.info(c_rpm.get('suggests'))
115                 logger.info(c_rpm.get('name'))
116
117     
118     # make tree of meta
119     for root in meta_info['root']:
120         root_node = make_meta_node(root[0], root[1])
121         view_ref[root[0]] = root_node
122         if root[0] in category_dict:
123             root_node['category'] = category_dict[root[0]]
124         if is_blank_ui_meta_node(root[0]):
125             name = root[0]
126             sub1_node = handle_ui_meta_node(name[-2:], root_node)
127         view_data.append(root_node)
128         
129     for sub1 in meta_info['sub1']:
130         sub1_node = make_meta_node(sub1[0], sub1[2])
131         view_ref[sub1[0]] = sub1_node
132         if is_blank_ui_meta_node(sub1[0]):
133             name = sub1[0]
134             sub1_node = handle_ui_meta_node(name[-2:], sub1_node)
135         # search root
136         if sub1[1] in view_ref:
137             # add to root node
138             if 'category' in view_ref[sub1[1]] and view_ref[sub1[1]]['category']:
139                 sub1_node['category'] = view_ref[sub1[1]]['category']
140             view_ref[sub1[1]]['nodes'].append(sub1_node)
141         else:
142             # If root-meta does not exist, sub1 is added to top-level
143             view_data.append(sub1_node)
144             
145     for sub2 in meta_info['sub2']:
146         sub2_node = make_meta_node(sub2[0], sub2[3])
147         view_ref[sub2[0]] = sub2_node
148         if is_blank_ui_meta_node(sub2[0]):
149             name = sub2[0]
150             sub1_node = handle_ui_meta_node(name[-2:], sub2_node)
151         # search sub1
152         if sub2[2] in view_ref:
153             if 'category' in view_ref[sub2[2]] and view_ref[sub2[2]]['category']:
154                 sub2_node['category'] = view_ref[sub2[2]]['category']
155             view_ref[sub2[2]]['nodes'].append(sub2_node)
156         # search root    
157         elif sub2[1] in view_ref: 
158             if view_ref[sub2[1]]['category']:
159                 sub2_node['category'] = view_ref[sub2[1]]['category']
160             # If sub1-meta does not exist, sub2 is added to child of root-meta
161             view_ref[sub2[1]]['nodes'].append(sub2_node)
162         else:
163             # If root-meta/sub1-meta does not exist, sub1 is added to top-level
164             view_data.append(sub2_node)
165     
166     # configure meta dependency tree (requires)
167     for meta_pkg in view_data:
168         set_meta_require(meta_pkg)
169         
170     #The remaining rpms are grouped into a MISC tree
171     misc_info = {}
172     misc_info['text'] = 'Advanced (individual packages)'
173     misc_info['nodes'] = []
174     for k, v in pkg_dict.iteritems():
175         # Pkg is not referenced from Meta-pkg
176         if not v.get('meta') and refer_count[v['id']] == 0:
177             misc_info['nodes'].append(make_node(v))
178     misc_info['nodes'] = sorted(misc_info['nodes'], key = lambda k: k['metaname'] if 'metaname' in k else k['text'])
179
180     view_data.append(misc_info)
181     logger.info('meta: %d, misc: %d', len(view_ref), len(misc_info['nodes']))
182     return view_data