[TIC-CORE] Initial Import
[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 re
25
26 class RepodataParser(object):
27     
28     def __init__(self, repodata_list):
29         self.repodata_list = repodata_list
30         
31     def _xml_parse(self, pkg_group, tree, tag_dic):
32         meta_prefix = 'building-block'
33         meta_prefix_root = 'building-block-root-'
34         meta_prefix_sub1 = 'building-block-sub1-'
35         meta_pattern = re.compile(''.join(['^', meta_prefix, '-(?P<meta>root|sub1|sub2)-(?P<pkgname>.+)']), re.I)
36         meta_sub1_pattern = re.compile("(?P<root>.+)-(?P<sub1>.+)")
37         meta_sub2_pattern = re.compile("(?P<root>.+)-(?P<sub1>.+)-(?P<sub2>.+)")
38
39         root = tree.getroot()
40         
41         pkg_list = pkg_group.get('pkg_list')
42         pkg2id = pkg_group.get('pkg2id')
43         provides2id = pkg_group.get('provides2id')
44         file2id = pkg_group.get('file2id')
45         meta_info = pkg_group.get('meta_info')
46         
47         pkg_id = len(pkg_list)
48         
49         for pkg in root.findall(tag_dic['package']):
50                     
51             pkg_name = pkg.findtext(tag_dic['name'])
52             
53             # check whether a package is duplicated. 
54             if pkg_name in pkg2id:
55                 #TODO: Apply to policy of duplication
56                 print('Package(', pkg_name, ') is duplicated. exclude the package')
57                 continue
58             else:
59                 pkg2id[pkg_name] = pkg_id
60                 
61             pkg_info = {}
62             pkg_info['name'] = pkg_name
63             pkg_info['text'] = pkg_name
64             
65             # Parsing meta-pkg using meta naming rule
66             meta_match = meta_pattern.search(pkg_info['name'])
67             if meta_match is not None:
68                 #print(meta_match.group(0), ', ', meta_match.group('meta'), ', ', meta_match.group('pkgname'))
69                 if meta_match.group('meta') == 'root':
70                     meta_info['root'].append([pkg_info['name']])
71                     pkg_info['meta'] = 'root'
72                 elif meta_match.group('meta') == 'sub1':
73                     sub1_match = meta_sub1_pattern.search(meta_match.group('pkgname'))
74                     meta_info['sub1'].append([pkg_info['name'],
75                                               ''.join([meta_prefix_root, sub1_match.group('root')]),
76                                               ])
77                     pkg_info['meta'] = 'sub1'
78                 elif meta_match.group('meta') == 'sub2':
79                     sub2_match = meta_sub2_pattern.search(meta_match.group('pkgname'))
80                     meta_info['sub2'].append([pkg_info['name'],
81                                               ''.join([meta_prefix_root, sub2_match.group('root')]),
82                                               ''.join([meta_prefix_sub1, sub2_match.group('root'),'-', sub2_match.group('sub1')])
83                                               ])
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         pkg_list = pkg_group.get('pkg_list')
159         pkg2id = pkg_group.get('pkg2id')
160         provides2id = pkg_group.get('provides2id')
161         file2id = pkg_group.get('file2id')
162         
163         for pkg_id in range(len(pkg_list)):
164             requires = pkg_list[pkg_id].get('requires')
165             if requires is not None:
166                 for req_info in requires:
167                     req_name = req_info['name']
168                     #TODO: Determine dependency search order
169                     if req_name in provides2id:
170                         #TODO: Select a package in provides (version?)
171                         req_info['id'] = provides2id[req_name][0]['id']
172                     elif req_name in pkg2id:
173                         req_info['id'] = pkg2id[req_name]
174                     elif req_name in file2id:
175                         req_info['id'] = file2id[req_name][0]['id']
176                     else:
177                         #TODO: Exception Check
178                         # the dependent package does not exist.
179                         #print('_req_parse::', req_name, ' does not exist')
180                         pass
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         #TODO: repo URL validation
209         
210         tree_list = []
211         try:
212             for repodata in self.repodata_list:
213                 tree = etree.parse(repodata['primary'])
214                 tree_list.append(tree)
215         except etree.XMLSyntaxError as e:
216             raise TICError('primary.xml syntax error.')
217         
218         tag_dic = self._get_tagname(tree_list[0])
219         
220         pkg_group = dict(pkg_list=[],
221                          pkg2id={},
222                          provides2id={},
223                          file2id={},
224                          meta_info=dict(root=[],sub1=[],sub2=[]))
225         
226         # parses the repodata (primary.xml)
227         for tree in tree_list:
228             self._xml_parse(pkg_group, tree, tag_dic)
229             
230         # set the requires id
231         self._prepare_requires_id(pkg_group)
232             
233         return pkg_group