2 # Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
5 # @author Chulwoo Shin <cw1.shin@samsung.com>
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
11 # http://www.apache.org/licenses/LICENSE-2.0
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.
22 from lxml import etree
23 from tic.utils.error import TICError
27 class RepodataParser(object):
29 def __init__(self, repodata_list):
30 self.repodata_list = repodata_list
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>.+)")
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')
49 pkg_id = len(pkg_list)
51 for pkg in root.findall(tag_dic['package']):
53 pkg_name = pkg.findtext(tag_dic['name'])
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)
61 pkg2id[pkg_name] = pkg_id
64 pkg_info['name'] = pkg_name
65 pkg_info['text'] = pkg_name
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'] = []
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']
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:
102 for rpm in requires_tag:
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:
114 for rpm in provides_tag:
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']
123 if rpm.attrib['name'] in provides2id:
124 provides2id[rpm.attrib['name']].append(provide)
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:
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:
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:
144 for file in format_tag.findall(tag_dic['file']):
147 f['name'] = file.text
148 if file.text in file2id:
149 file2id[file.text].append(f)
151 file2id[file.text] = [f]
152 dep_list.append(file.text)
153 pkg_info['file'] = dep_list;
154 pkg_list.append(pkg_info)
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')
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']
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'))
182 def _get_tagname(self, tree):
183 root = tree.getroot()
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]
205 if not self.repodata_list:
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)
216 tag_dic = self._get_tagname(tree_list[0])
218 pkg_group = dict(pkg_list=[],
222 meta_info=dict(root=[], sub1=[], sub2=[]))
224 # parses the repodata (primary.xml)
225 for tree in tree_list:
226 self._xml_parse(pkg_group, tree, tag_dic)
228 # set the requires id
229 self._prepare_requires_id(pkg_group)