f979ca56f32b4a8e7f755972b0855a0e171cb623
[archive/20170607/tools/tic-core.git] / tic / parser / repo_parser.py
1 #!/usr/bin/python
2 # Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
3 #
4 # Contact: 
5 # @author Chulwoo Shin <cw1.shin@samsung.com>
6
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
10 #
11 # http://www.apache.org/licenses/LICENSE-2.0
12 #
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
18 #
19 # Contributors:
20 # - S-Core Co., Ltd
21
22 from lxml import etree
23 from tic.utils.error import TICError
24 import logging
25 import re
26
27 class RepodataParser(object):
28     
29     def __init__(self, repodata_list):
30         self.repodata_list = repodata_list
31         
32     def _xml_parse(self, pkg_group, tree, tag_dic):
33         logger = logging.getLogger(__name__)
34         meta_prefix = 'building-block'
35         meta_prefix_root = 'building-block-root-'
36         meta_prefix_sub1 = 'building-block-sub1-'
37         meta_pattern = re.compile(''.join(['^', meta_prefix, '-(?P<meta>root|sub1|sub2)-(?P<pkgname>.+)']), re.I)
38         meta_sub1_pattern = re.compile("(?P<root>.+)-(?P<sub1>.+)")
39         meta_sub2_pattern = re.compile("(?P<root>.+)-(?P<sub1>.+)-(?P<sub2>.+)")
40
41         root = tree.getroot()
42         
43         pkg_list = pkg_group.get('pkg_list')
44         pkg2id = pkg_group.get('pkg2id')
45         provides2id = pkg_group.get('provides2id')
46         file2id = pkg_group.get('file2id')
47         meta_info = pkg_group.get('meta_info')
48         
49         pkg_id = len(pkg_list)
50         
51         for pkg in root.findall(tag_dic['package']):
52                     
53             pkg_name = pkg.findtext(tag_dic['name'])
54             
55             # check whether a package is duplicated. 
56             if pkg_name in pkg2id:
57                 #TODO: Apply to policy of duplication
58                 logger.warning('package(%s) is duplicated. exclude this package', pkg_name)
59                 continue
60             else:
61                 pkg2id[pkg_name] = pkg_id
62                 
63             pkg_info = {}
64             pkg_info['name'] = pkg_name
65             pkg_info['text'] = pkg_name
66             
67             # Parsing meta-pkg using meta naming rule
68             meta_match = meta_pattern.search(pkg_info['name'])
69             if meta_match is not None:
70                 #print(meta_match.group(0), ', ', meta_match.group('meta'), ', ', meta_match.group('pkgname'))
71                 if meta_match.group('meta') == 'root':
72                     meta_info['root'].append([pkg_info['name']])
73                     pkg_info['meta'] = 'root'
74                 elif meta_match.group('meta') == 'sub1':
75                     sub1_match = meta_sub1_pattern.search(meta_match.group('pkgname'))
76                     meta_info['sub1'].append([pkg_info['name'],
77                                               ''.join([meta_prefix_root, sub1_match.group('root')])])
78                     pkg_info['meta'] = 'sub1'
79                 elif meta_match.group('meta') == 'sub2':
80                     sub2_match = meta_sub2_pattern.search(meta_match.group('pkgname'))
81                     meta_info['sub2'].append([pkg_info['name'],
82                                               ''.join([meta_prefix_root, sub2_match.group('root')]),
83                                               ''.join([meta_prefix_sub1, sub2_match.group('root'),'-', sub2_match.group('sub1')])])
84                     pkg_info['meta'] = 'sub2'
85                 pkg_info['nodes'] = []
86             
87             pkg_info['arch'] = pkg.findtext(tag_dic['arch'])
88             pkg_info['version'] = pkg.find(tag_dic['version']).attrib['ver']
89             pkg_info['checksum'] = pkg.findtext(tag_dic['checksum'])
90             pkg_info['summary'] = pkg.findtext(tag_dic['summary'])
91             pkg_info['description'] = pkg.findtext(tag_dic['description'])
92             pkg_info['location'] = pkg.find(tag_dic['location']).attrib['href']
93             size_tag = pkg.find(tag_dic['size'])
94             pkg_info['size'] = size_tag.attrib['package']
95             pkg_info['installed'] = size_tag.attrib['installed']
96             
97             format_tag = pkg.find(tag_dic['format'])
98             if(format_tag is not None):
99                 requires_tag = format_tag.find(tag_dic['requires'])
100                 if requires_tag is not None:
101                     dep_list = []
102                     for rpm in requires_tag:
103                         req_rpm = {}
104                         req_rpm['name'] = rpm.attrib['name']
105                         if 'ver' in rpm.attrib:
106                             req_rpm['ver'] = rpm.attrib['ver']
107                         if 'flags' in rpm.attrib:
108                             req_rpm['flags'] = rpm.attrib['flags']
109                         dep_list.append(req_rpm)
110                     pkg_info['requires'] = dep_list;
111                 provides_tag = format_tag.find(tag_dic['provides'])
112                 if provides_tag is not None:
113                     dep_list = []
114                     for rpm in provides_tag:
115                         provide = {}
116                         provide['id'] = pkg_id
117                         provide['name'] = rpm.attrib['name']
118                         if 'ver' in rpm.attrib:
119                             provide['ver'] = rpm.attrib['ver']
120                         if 'flags' in rpm.attrib:
121                             provide['flags'] = rpm.attrib['flags']
122                         
123                         if rpm.attrib['name'] in provides2id:
124                             provides2id[rpm.attrib['name']].append(provide)
125                         else:
126                             provides2id[rpm.attrib['name']] = [provide]
127                         dep_list.append(rpm.attrib['name'])
128                     pkg_info['provides'] = dep_list;
129                 conflicts_tag = format_tag.find(tag_dic['conflicts'])
130                 if conflicts_tag is not None:
131                     dep_list = []
132                     for rpm in conflicts_tag:
133                         dep_list.append(rpm.attrib['name'])
134                     pkg_info['conflicts'] = dep_list;
135                 suggests_tag = format_tag.find(tag_dic['suggests'])
136                 if suggests_tag is not None:
137                     dep_list = []
138                     for rpm in suggests_tag:
139                         dep_list.append(rpm.attrib['name'])
140                     pkg_info['suggests'] = dep_list;
141                 file_tag = format_tag.find(tag_dic['file'])
142                 if file_tag is not None:
143                     dep_list = []
144                     for file in format_tag.findall(tag_dic['file']):
145                         f = {}
146                         f['id'] = pkg_id
147                         f['name'] = file.text
148                         if file.text in file2id:
149                             file2id[file.text].append(f)
150                         else:
151                             file2id[file.text] = [f]
152                         dep_list.append(file.text)
153                     pkg_info['file'] = dep_list;
154             pkg_list.append(pkg_info)
155             pkg_id += 1
156     
157     def _prepare_requires_id(self, pkg_group):
158         logger = logging.getLogger(__name__)
159         pkg_list = pkg_group.get('pkg_list')
160         pkg2id = pkg_group.get('pkg2id')
161         provides2id = pkg_group.get('provides2id')
162         file2id = pkg_group.get('file2id')
163         
164         for pkg_id in range(len(pkg_list)):
165             requires = pkg_list[pkg_id].get('requires')
166             if requires is not None:
167                 for req_info in requires:
168                     req_name = req_info['name']
169                     #TODO: Determine dependency search order
170                     if req_name in provides2id:
171                         #TODO: Select a package in provides (version?)
172                         req_info['id'] = provides2id[req_name][0]['id']
173                     elif req_name in pkg2id:
174                         req_info['id'] = pkg2id[req_name]
175                     elif req_name in file2id:
176                         req_info['id'] = file2id[req_name][0]['id']
177                     else:
178                         #TODO: Exception Check
179                         # the dependent package does not exist.
180                         logger.warning('"%s" required by "%s" does not exist.', req_name, pkg_list[pkg_id].get('name'))
181     
182     def _get_tagname(self, tree):
183         root = tree.getroot()
184         tags = {}
185         # xmlns = re.sub('metadata$', '', root.tag) 
186         tags['metadata'] = '{%s}metadata' % root.nsmap[None]
187         tags['package'] = '{%s}package' % root.nsmap[None]
188         tags['name'] = '{%s}name' % root.nsmap[None]
189         tags['arch'] = '{%s}arch' % root.nsmap[None]
190         tags['version'] = '{%s}version' % root.nsmap[None]
191         tags['checksum'] = '{%s}checksum' % root.nsmap[None]
192         tags['summary'] = '{%s}summary' % root.nsmap[None]
193         tags['description'] = '{%s}description' % root.nsmap[None]
194         tags['location'] = '{%s}location' % root.nsmap[None]
195         tags['size'] = '{%s}size' % root.nsmap[None]
196         tags['format'] = '{%s}format' % root.nsmap[None]
197         tags['requires'] = '{%s}requires' % root.nsmap['rpm']
198         tags['provides'] = '{%s}provides' % root.nsmap['rpm']
199         tags['conflicts'] = '{%s}conflicts' % root.nsmap['rpm']
200         tags['suggests'] = '{%s}suggests' % root.nsmap['rpm']
201         tags['file'] = '{%s}file' % root.nsmap[None]
202         return tags
203
204     def parse(self):
205         if not self.repodata_list:
206             return None
207         
208         tree_list = []
209         try:
210             for repodata in self.repodata_list:
211                 tree = etree.parse(repodata['primary'])
212                 tree_list.append(tree)
213         except etree.XMLSyntaxError as e:
214             raise TICError('primary.xml syntax error. %s', e)
215         
216         tag_dic = self._get_tagname(tree_list[0])
217         
218         pkg_group = dict(pkg_list=[],
219                          pkg2id={},
220                          provides2id={},
221                          file2id={},
222                          meta_info=dict(root=[], sub1=[], sub2=[]))
223         
224         # parses the repodata (primary.xml)
225         for tree in tree_list:
226             self._xml_parse(pkg_group, tree, tag_dic)
227             
228         # set the requires id
229         self._prepare_requires_id(pkg_group)
230             
231         return pkg_group