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
24 from tic.utils.rpmmisc import archPolicies, default_arch
28 meta_prefix = 'building-blocks'
29 meta_prefix_root = 'building-blocks-root-'
30 meta_prefix_sub1 = 'building-blocks-sub1-'
31 meta_pattern = re.compile(''.join(['^', meta_prefix, '-(?P<meta>root|sub1|sub2)-(?P<pkgname>.+)']), re.I)
32 meta_sub1_pattern = re.compile("(?P<root>.+)-(?P<sub1>.+)")
33 meta_sub2_pattern = re.compile("(?P<root>.+)-(?P<sub1>.+)-(?P<sub2>.+)")
35 class RepodataParser(object):
37 def __init__(self, arch, repodata_list):
39 self.repodata_list = repodata_list
41 def _xml_parse(self, pkg_group, pkg_list, tag_dic):
43 def _set_version(element, tag):
44 if 'ver' in tag.attrib:
45 element['ver'] = tag.attrib['ver']
46 if 'rel' in tag.attrib:
47 element['rel'] = tag.attrib['rel']
48 if 'epoch' in tag.attrib:
49 element['epoch'] = tag.attrib['epoch']
50 if 'flags' in tag.attrib:
51 element['flags'] = tag.attrib['flags']
53 pkg_dict = pkg_group.get('pkg_dict')
54 provides_dict = pkg_group.get('provides')
55 files_dict = pkg_group.get('files')
56 meta_info = pkg_group.get('meta_info')
57 pkg_id = len(pkg_dict)
60 pkg_name = pkg.findtext(tag_dic['name'])
62 # check whether a package is duplicated.
63 if pkg_name in pkg_dict:
64 # TODO: Apply to policy of duplication
65 # logger.warning('package(%s) is duplicated. exclude this package', pkg_name)
69 pkg_info['id'] = pkg_id
70 pkg_info['name'] = pkg_name
71 pkg_info['arch'] = pkg.findtext(tag_dic['arch'])
72 pkg_info['selfChecked'] = False # for web-ui tree
74 # Parsing meta-pkg using meta naming rule
75 meta_match = meta_pattern.search(pkg_info['name'])
76 if meta_match is not None:
77 #print(meta_match.group(0), ', ', meta_match.group('meta'), ', ', meta_match.group('pkgname'))
78 if meta_match.group('meta') == 'root':
79 meta_info['root'].append([pkg_info['name']])
80 pkg_info['meta'] = 'root'
81 elif meta_match.group('meta') == 'sub1':
82 sub1_match = meta_sub1_pattern.search(meta_match.group('pkgname'))
83 meta_info['sub1'].append([pkg_info['name'],
84 ''.join([meta_prefix_root, sub1_match.group('root')])])
85 pkg_info['meta'] = 'sub1'
86 elif meta_match.group('meta') == 'sub2':
87 sub2_match = meta_sub2_pattern.search(meta_match.group('pkgname'))
88 meta_info['sub2'].append([pkg_info['name'],
89 ''.join([meta_prefix_root, sub2_match.group('root')]),
90 ''.join([meta_prefix_sub1, sub2_match.group('root'),'-', sub2_match.group('sub1')])])
91 pkg_info['meta'] = 'sub2'
94 ver_tag = pkg.find(tag_dic['version'])
95 pkg_info['version'] = {'epoch':ver_tag.attrib['epoch'],
96 'ver':ver_tag.attrib['ver'],
97 'rel':ver_tag.attrib['rel']}
98 pkg_info['checksum'] = pkg.findtext(tag_dic['checksum'])
99 pkg_info['summary'] = pkg.findtext(tag_dic['summary'])
100 pkg_info['description'] = pkg.findtext(tag_dic['description'])
101 pkg_info['location'] = pkg.find(tag_dic['location']).attrib['href']
102 size_tag = pkg.find(tag_dic['size'])
103 pkg_info['size'] = size_tag.attrib['package']
104 pkg_info['installed'] = size_tag.attrib['installed']
106 format_tag = pkg.find(tag_dic['format'])
107 if(format_tag is not None):
108 requires_tag = format_tag.find(tag_dic['requires'])
109 if requires_tag is not None:
111 for rpm in requires_tag:
113 require['name'] = rpm.attrib['name']
114 _set_version(require, rpm)
115 dep_list.append(require)
116 pkg_info['requires'] = dep_list;
117 provides_tag = format_tag.find(tag_dic['provides'])
118 if provides_tag is not None:
120 for rpm in provides_tag:
122 provide['name'] = rpm.attrib['name']
123 _set_version(provide, rpm)
124 if provide.get('ver') and not provide.get('rel') and pkg_info['version']['rel']:
125 provide['rel'] = pkg_info['version']['rel'];
127 if rpm.attrib['name'] in provides_dict:
128 provides_dict[rpm.attrib['name']].append({'name': pkg_name, 'data': provide})
130 provides_dict[rpm.attrib['name']] = [{'name': pkg_name, 'data': provide}]
131 dep_list.append(provide)
132 pkg_info['provides'] = dep_list;
133 conflicts_tag = format_tag.find(tag_dic['conflicts'])
134 if conflicts_tag is not None:
136 for rpm in conflicts_tag:
138 conflict['name'] = rpm.attrib['name']
139 _set_version(conflict, rpm)
140 dep_list.append(conflict)
141 pkg_info['conflicts'] = dep_list;
142 recommends_tag = format_tag.find(tag_dic['recommends'])
143 if recommends_tag is not None:
145 for rpm in recommends_tag:
147 recommend['name'] = rpm.attrib['name']
148 _set_version(recommend, rpm)
149 dep_list.append(recommend)
150 pkg_info['recommends'] = dep_list;
151 suggests_tag = format_tag.find(tag_dic['suggests'])
152 if suggests_tag is not None:
154 for rpm in suggests_tag:
155 dep_list.append(rpm.attrib['name'])
156 pkg_info['suggests'] = dep_list;
157 file_tag = format_tag.find(tag_dic['file'])
158 if file_tag is not None:
160 for file_t in format_tag.findall(tag_dic['file']):
161 if file_t.text in files_dict:
162 files_dict[file_t.text].append(pkg_name)
164 files_dict[file_t.text] = [pkg_name]
165 dep_list.append(file_t.text)
166 pkg_info['file'] = dep_list;
167 pkg_dict[pkg_name] = pkg_info
170 def _prepare_requires_id(self, pkg_group):
171 logger = logging.getLogger(__name__)
172 pkg_list = pkg_group.get('pkg_list')
173 pkg2id = pkg_group.get('pkg2id')
174 provides2id = pkg_group.get('provides2id')
175 file2id = pkg_group.get('file2id')
177 for pkg_id in range(len(pkg_list)):
178 requires = pkg_list[pkg_id].get('requires')
179 if requires is not None:
180 for req_info in requires:
181 req_name = req_info['name']
182 #TODO: Determine dependency search order
183 if req_name in provides2id:
184 #TODO: Select a package in provides (version?)
185 req_info['id'] = provides2id[req_name][0]['id']
186 elif req_name in pkg2id:
187 req_info['id'] = pkg2id[req_name]
188 elif req_name in file2id:
189 req_info['id'] = file2id[req_name][0]['id']
191 #TODO: Exception Check
192 # the dependent package does not exist.
193 logger.warning('"%s" required by "%s" does not exist.', req_name, pkg_list[pkg_id].get('name'))
195 def _get_tagname(self, root):
197 # xmlns = re.sub('metadata$', '', root.tag)
198 tags['metadata'] = '{%s}metadata' % root.nsmap[None]
199 tags['package'] = '{%s}package' % root.nsmap[None]
200 tags['name'] = '{%s}name' % root.nsmap[None]
201 tags['arch'] = '{%s}arch' % root.nsmap[None]
202 tags['version'] = '{%s}version' % root.nsmap[None]
203 tags['checksum'] = '{%s}checksum' % root.nsmap[None]
204 tags['summary'] = '{%s}summary' % root.nsmap[None]
205 tags['description'] = '{%s}description' % root.nsmap[None]
206 tags['location'] = '{%s}location' % root.nsmap[None]
207 tags['size'] = '{%s}size' % root.nsmap[None]
208 tags['format'] = '{%s}format' % root.nsmap[None]
209 tags['requires'] = '{%s}requires' % root.nsmap['rpm']
210 tags['provides'] = '{%s}provides' % root.nsmap['rpm']
211 tags['conflicts'] = '{%s}conflicts' % root.nsmap['rpm']
212 tags['suggests'] = '{%s}suggests' % root.nsmap['rpm']
213 tags['recommends'] = '{%s}recommends' % root.nsmap['rpm']
214 tags['file'] = '{%s}file' % root.nsmap[None]
217 def _filtering_data_based_arch(self, xml_list, tag_dic):
219 for xml_root in xml_list:
221 for pkg_elm in xml_root.findall(tag_dic['package']):
222 pkg_arch = pkg_elm.findtext(tag_dic['arch'])
223 if pkg_arch not in archPolicies[self.arch] and pkg_arch not in default_arch:
225 if not pkg_data.get(pkg_arch):
226 pkg_data[pkg_arch] = []
227 pkg_data[pkg_arch].append(pkg_elm)
228 ret_list.append(pkg_data)
232 if not self.repodata_list:
237 for repodata in self.repodata_list:
238 tree = etree.parse(repodata['primary'])
239 xml_list.append(tree.getroot())
240 except etree.XMLSyntaxError as e:
241 raise TICError('primary.xml syntax error. %s', e)
243 tag_dic = self._get_tagname(xml_list[0])
245 # TODO: temporary code (should be deleted)
246 # meta_string='<?xml version="1.0" encoding="UTF-8"?><metadata xmlns="http://linux.duke.edu/metadata/common" xmlns:rpm="http://linux.duke.edu/metadata/rpm" packages="1467"><package type="rpm"><name>building-blocks-root-chooseonlyone_Kernel</name><arch>armv7l</arch><version epoch="0" ver="2.0.4" rel="4.2" vcs="platform/upstream/SDL#5f9405ba696ad79a0e05150430fe69e874f8280d" /><checksum type="sha256" pkgid="YES">6f74666eb89e1addc4ce75e25f3e639bbfdd8798fc848a6b7027501070567dcf</checksum><summary>Linux Kernel</summary><description>Include Linux Kernel in the Platform Image</description><packager /><url>http://tizen.org</url><time file="1487645040" build="1487645034" /><size package="2088" installed="0" archive="124" /><location href="armv7l/building-blocks-root-Kernel-0.0.1-1.1.armv7l.rpm" /><format><rpm:license>Apache-2</rpm:license><rpm:vendor>tizen</rpm:vendor><rpm:group>Meta</rpm:group><rpm:buildhost>w08</rpm:buildhost><rpm:sourcerpm>building-blocks-0.0.1-1.1.src.rpm</rpm:sourcerpm><rpm:header-range start="280" end="1964" /><rpm:requires><rpm:entry name="linux-kernel" flags="GE" epoch="0" ver="3.10" /></rpm:requires></format></package></metadata>'
247 # xml_list.append(etree.fromstring(meta_string))
249 filter_data = self._filtering_data_based_arch(xml_list, tag_dic)
251 pkg_group = dict(pkg_dict={},
256 meta_info=dict(root=[], sub1=[], sub2=[]))
258 # parses the repodata (primary.xml)
259 # for xml_root in xml_list:
260 # self._xml_parse(pkg_group, xml_root, tag_dic)
261 for xml_data in filter_data:
262 for arch in archPolicies[self.arch]:
264 self._xml_parse(pkg_group, xml_data[arch], tag_dic)
266 for arch in default_arch:
268 self._xml_parse(pkg_group, xml_data[arch], tag_dic)
270 # set the requires id
271 #self._prepare_requires_id(pkg_group)