4a87fecb53a66b5c92939301c8fd21234ba86fbc
[platform/upstream/libzypp.git] / zypp / parser / yum / FileReaderBaseImpl.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/parser/yum/FileReaderBaseImpl.cc
10  * Implementation of shared code for yum::*FileReaders.
11  */
12 #include <sstream>
13
14 #include "zypp/base/Logger.h"
15 #include "zypp/base/Function.h"
16 #include "zypp/Arch.h"
17 #include "zypp/Edition.h"
18 #include "zypp/TranslatedText.h"
19 #include "zypp/ByteCount.h"
20
21 #include "zypp/parser/ParseException.h"
22 #include "zypp/parser/yum/FileReaderBaseImpl.h"
23
24 using namespace std;
25 using namespace zypp::xml;
26
27 namespace zypp
28 {
29   namespace parser
30   {
31     namespace yum
32     {
33
34
35   FileReaderBase::BaseImpl::BaseImpl()
36     : _expect_rpm_entry(false), _dtype(zypp::Dep::REQUIRES)
37   {}
38
39   // --------------------------------------------------------------------------
40
41   /*
42    * xpath and multiplicity of processed nodes are included in the code
43    * for convenience:
44    *
45    * // xpath: <xpath> (?|*|+)
46    *
47    * if multiplicity is ommited, then the node has multiplicity 'one'.
48    */
49
50   // --------------------------------------------------------------------------
51
52   bool FileReaderBase::BaseImpl::consumePackageNode(xml::Reader & reader_r, data::Packagebase_Ptr & package_ptr)
53   {
54     // DBG << "**node: " << reader_r->name() << " (" << reader_r->nodeType() << ") tagpath = " << _tagpath << endl;
55     if (!isBeingProcessed(tag_package))
56       ZYPP_THROW(ParseException("consumePackageNode() called outside of package element"));
57
58     if (isBeingProcessed(tag_format) && consumeFormatNode(reader_r, package_ptr))
59       return true;
60
61     if (reader_r->nodeType() == XML_READER_TYPE_ELEMENT)
62     {
63       // xpath: //package/name
64       if (reader_r->name() == "name")
65       {
66         package_ptr->name = reader_r.nodeText().asString();
67         return true;
68       }
69
70       // xpath: //package/arch
71       if (reader_r->name() == "arch")
72       {
73         string arch = reader_r.nodeText().asString();
74         // create SrcPackage instead of Package for source packages
75         if (arch == "src" || arch == "nosrc")
76         {
77           arch = "noarch";
78           data::Packagebase_Ptr srcpkg = new data::SrcPackage;
79           // we have read name only so far, copying only the name
80           srcpkg->name = package_ptr->name;
81           // package_ptr will point to a SrcPackage from now on
82           package_ptr.swap(srcpkg);
83         }
84         package_ptr->arch.swap(arch);
85         return true;
86       }
87
88       // xpath: //package/version
89       if (reader_r->name() == "version")
90       {
91         if (reader_r->getAttribute("epoch").asString().empty());
92           package_ptr->edition += (reader_r->getAttribute("epoch").asString()+":");
93         
94         package_ptr->edition += ( reader_r->getAttribute("ver").asString() + "-" + reader_r->getAttribute("rel").asString() );
95         return true;
96       }
97
98       // xpath: //package/checksum
99       if (reader_r->name() == "checksum")
100       {
101         package_ptr->repositoryLocation.setChecksum(CheckSum(
102                             reader_r->getAttribute("type").asString(),
103                             reader_r.nodeText().asString()));
104         // ignoring pkgid attribute
105         return true;
106       }
107
108       // xpath: //package/summary (*)
109       if (reader_r->name() == "summary")
110       {
111         Locale locale(reader_r->getAttribute("lang").asString());
112         package_ptr->summary.setText(
113             reader_r.nodeText().asString(), locale);
114         return true;
115       }
116
117       // xpath: //package/description (*)
118       if (reader_r->name() == "description")
119       {
120         Locale locale(reader_r->getAttribute("lang").asString());
121         package_ptr->description.setText(
122             reader_r.nodeText().asString(), locale);
123         return true;
124       }
125
126       // xpath: //package/packager
127       if (reader_r->name() == "packager")
128       {
129         package_ptr->packager = reader_r.nodeText().asString();
130         return true;
131       }
132
133       // xpath: //package/url
134       if (reader_r->name() == "url")
135       {
136         package_ptr->url = reader_r.nodeText().asString();
137         return true;
138       }
139
140       // xpath: //package/time
141       if (reader_r->name() == "time")
142       {
143         package_ptr->buildTime = reader_r->getAttribute("build").asString();
144         // ignoring reader_r->getAttribute("file").asString(); (rpm file timestamp)
145         return true;
146       }
147
148       // xpath: //package/size
149       if (reader_r->name() == "size")
150       {
151         //! \todo what's 'archive' size of the package (it is neither the rpm file size nor its installed size)
152         // reader_r->getAttribute("archive").asString();
153
154         // installed size
155         package_ptr->installedSize = str::strtonum<ByteCount::SizeType>( reader_r->getAttribute("installed").asString() );
156
157         // rpm package size
158         package_ptr->repositoryLocation.setDownloadSize(str::strtonum<ByteCount::SizeType>( reader_r->getAttribute("package").asString() ));
159
160         return true;
161       }
162
163       // xpath: //package/location
164       if (reader_r->name() == "location")
165       {
166         package_ptr->repositoryLocation.setLocation(reader_r->getAttribute("href").asString(), 1);
167         return true;
168       }
169
170       // xpath: //package/format
171       if (reader_r->name() == "format")
172       {
173         tag(tag_format);
174         return true;
175       }
176     }
177
178     else if ( reader_r->nodeType() == XML_READER_TYPE_END_ELEMENT )
179     {
180       // xpath: //package
181       if (reader_r->name() == "package")
182       {
183         // indicate that further processing is required
184         // e.g. caller needs to to check for </package> to trigger some action
185         return false;
186       }
187     }
188
189     return true;
190   }
191
192   bool FileReaderBase::BaseImpl::editionStringFromAttrs( xml::Reader & reader_r, string &edition )
193   {
194     string result;
195     if ( ! reader_r->getAttribute("epoch").asString().empty() )
196       result += (reader_r->getAttribute("epoch").asString() + ":");
197
198     result += reader_r->getAttribute("ver").asString();
199     result += ( "-" + reader_r->getAttribute("ver").asString());
200     result.swap(edition);
201     return true;
202   }
203
204   // --------------( consume <format> tag )------------------------------------
205
206   bool FileReaderBase::BaseImpl::consumeFormatNode(
207     xml::Reader & reader_r, data::Packagebase_Ptr & package_ptr)
208   {
209     if (consumeDependency(reader_r, package_ptr->deps))
210       // this node has been a dependency, which has been handled by
211       // consumeDependency(), so return right away.
212       return true;
213
214     // DBG << "format subtag: " << reader_r->name() << endl;
215
216     if (reader_r->nodeType() == XML_READER_TYPE_ELEMENT)
217     {
218       // xpath: //format/rpm:license
219       if (reader_r->name() == "rpm:license")
220       {
221         package_ptr->license = reader_r.nodeText().asString();
222         return true;
223       }
224
225       // xpath: //format/rpm:vendor
226       if (reader_r->name() == "rpm:vendor")
227       {
228         package_ptr->vendor = reader_r.nodeText().asString();
229         return true;
230       }
231
232       // xpath: //format/rpm:group
233       if (reader_r->name() == "rpm:group")
234       {
235         package_ptr->group = reader_r.nodeText().asString();
236         return true;
237       }
238
239       // xpath: //format/rpm:buildhost
240       if (reader_r->name() == "rpm:buildhost")
241       {
242         package_ptr->buildhost = reader_r.nodeText().asString();
243         return true;
244       }
245
246       //! \todo xpath: //format/rpm:sourcerpm where to store this?
247       if (reader_r->name() == "rpm:sourcerpm")
248       {
249         //package->source = reader_r.nodeText().asString();
250         return true;
251       }
252
253       //! \todo xpath: //format/rpm:header-range what is this?
254       if (reader_r->name() == "rpm:header-range")
255       {
256         //reader_r->getAttribute("start").asString(),
257         //reader_r->getAttribute("end").asString(),
258         return true;
259       }
260
261       // file entries listed outside of filelists.xml to be treated
262       // like rpm:provides
263       // xpath: //format/file (*)
264       if (reader_r->name() == "file")
265       {
266         // insert file dependency into the list
267         package_ptr->deps[Dep::PROVIDES].insert(
268           zypp::capability::parse(
269             ResTraits<Package>::kind,
270             reader_r.nodeText().asString()));
271         return true;
272       }
273
274       // xpath: //format/suse:authors/suse:author (+)
275       // but tolerating multiplicity (*)
276       if (reader_r->name() == "suse:author")
277       {
278         package_ptr->authors.push_back(reader_r.nodeText().asString());
279         return true;
280       }
281
282       // xpath: //format/suse:keywords (?)
283       // xpath: //format/suse:keywords/suse:keyword (+)
284       if (reader_r->name() == "suse:keyword")
285       {
286         package_ptr->keywords.insert(reader_r.nodeText().asString());
287         return true;
288       }
289
290       //! \todo xpath: //format/suse:dirsizes (?)
291
292       // xpath: //format/suse:install-only (?)
293       if (reader_r->name() == "suse:install-only")
294       {
295         package_ptr->installOnly = true;
296         return true;
297       }
298
299       // xpath: //format/suse:license-to-confirm (*)
300       //! \todo this is ambiguous - fix the rnc schema
301       if (reader_r->name() == "suse:license-to-confirm")
302       {
303         Locale locale(reader_r->getAttribute("lang").asString());
304         package_ptr->licenseToConfirm.setText(
305             reader_r.nodeText().asString(), locale);
306         return true;
307       }
308     }
309     else if (reader_r->nodeType() == XML_READER_TYPE_END_ELEMENT)
310     {
311       // xpath: //format
312       if (reader_r->name() == "format")
313       {
314         toParentTag();
315         return true;
316       }
317     }
318
319     return true;
320   }
321
322   // --------------------------------------------------------------------------
323
324   bool FileReaderBase::BaseImpl::consumeDependency(
325     xml::Reader & reader_r, data::Dependencies & deps_r)
326   {
327     if (reader_r->nodeType() == XML_READER_TYPE_ELEMENT)
328     {
329       // xpath: //format/*/rpm:entry | //format/suse-freshens/suse:entry (+)
330       if (reader_r->name() == "rpm:entry" | reader_r->name() == "suse:entry")
331       {
332         if (!_expect_rpm_entry)
333           ZYPP_THROW(ParseException("rpm:entry found when not expected"));
334
335         // read kind of resolvable this entry refers, default to Package
336         string kind_str = reader_r->getAttribute("kind").asString();
337         Resolvable::Kind kind;
338         if (kind_str.empty())
339            kind = ResTraits<Package>::kind;
340         else
341           kind = Resolvable::Kind(kind_str);
342
343         // Check whether this is actually a prerequires dependency.
344         // If so, it will be stored in deps_r as Dep::PREREQUIRES
345         // instead of Dep::REQUIRES (a prerequires can appear as part
346         // of requires dependencies only).
347         bool pre = false;
348         if (reader_r->getAttribute("pre").asString() == "1")
349         {
350           if (_dtype.inSwitch() != Dep::REQUIRES_e)
351             ZYPP_THROW(ParseException("pre=\"1\" found for non-requires dependency"));
352           pre = true;
353         }
354 /*
355         DBG << "got rpm:entry for " << _dtype << ": "
356             << reader_r->getAttribute("name").asString()
357             << " " << edition << " (" << kind << ")" << endl;
358 */
359
360         string version = reader_r->getAttribute("ver").asString();
361
362         if (version.empty())
363         {
364           // insert unversion dependency into the list
365           deps_r[pre ? Dep::PREREQUIRES : _dtype].insert(
366             zypp::capability::parse(
367               kind, reader_r->getAttribute("name").asString()
368             )
369           );
370         }
371         else
372         {
373           Edition edition(
374             version,
375             reader_r->getAttribute("rel").asString(),
376             reader_r->getAttribute("epoch").asString()
377           );
378
379           // insert versioned dependency into the list
380           deps_r[pre ? Dep::PREREQUIRES : _dtype].insert(
381             zypp::capability::parse(
382               kind,
383               reader_r->getAttribute("name").asString(),
384               Rel(reader_r->getAttribute("flags").asString()),
385               edition
386             )
387           );
388         }
389
390         //! \todo check <rpm:entry name="/bin/sh" pre="1">
391       }
392
393       // xpath: //format/rpm:provides (?)
394       if (reader_r->name() == "rpm:provides")
395       {
396         _dtype = zypp::Dep::PROVIDES;
397         _expect_rpm_entry = true;
398         return true;
399       }
400       // xpath: //format/rpm:conflicts (?)
401       if (reader_r->name() == "rpm:conflicts")
402       {
403         _dtype = zypp::Dep::CONFLICTS;
404         _expect_rpm_entry = true;
405         return true;
406       }
407       // xpath: //format/rpm:obsoletes (?)
408       if (reader_r->name() == "rpm:obsoletes")
409       {
410         _dtype = zypp::Dep::OBSOLETES;
411         _expect_rpm_entry = true;
412         return true;
413       }
414       // xpath: //format/rpm:requires (?)
415       if (reader_r->name() == "rpm:requires")
416       {
417         _dtype = zypp::Dep::REQUIRES;
418         _expect_rpm_entry = true;
419         return true;
420       }
421       // xpath: //format/rpm:recommends (?)
422       if (reader_r->name() == "rpm:recommends")
423       {
424         _dtype = zypp::Dep::RECOMMENDS;
425         _expect_rpm_entry = true;
426         return true;
427       }
428       // xpath: //format/rpm:enhances (?)
429       if (reader_r->name() == "rpm:enhances")
430       {
431         _dtype = zypp::Dep::ENHANCES;
432         _expect_rpm_entry = true;
433         return true;
434       }
435       // xpath: //format/rpm:supplements (?)
436       if (reader_r->name() == "rpm:supplements")
437       {
438         _dtype = zypp::Dep::SUPPLEMENTS;
439         _expect_rpm_entry = true;
440         return true;
441       }
442       // xpath: //format/rpm:suggests (?)
443       if (reader_r->name() == "rpm:suggests")
444       {
445         _dtype = zypp::Dep::SUGGESTS;
446         _expect_rpm_entry = true;
447         return true;
448       }
449       // xpath: //format/suse:freshens (?)
450       if (reader_r->name() == "suse:freshens")
451       {
452         _dtype = zypp::Dep::FRESHENS;
453         _expect_rpm_entry = true;
454       }
455     }
456     else if (reader_r->nodeType() == XML_READER_TYPE_END_ELEMENT)
457     {
458       // xpath: //format/* (?)
459       if (reader_r->name() == "rpm:requires"
460           || reader_r->name() == "rpm:provides"
461           || reader_r->name() == "rpm:conflicts"
462           || reader_r->name() == "rpm:obsoletes"
463           || reader_r->name() == "rpm:recommends"
464           || reader_r->name() == "rpm:enhances"
465           || reader_r->name() == "rpm:supplements"
466           || reader_r->name() == "rpm:suggests"
467           || reader_r->name() == "suse:freshens")
468       {
469         _expect_rpm_entry = false;
470         return true;
471       }
472     }
473
474     // tell the caller this has not been a dependency tag (i.e. not processed)
475     return false;
476   }
477
478   // --------------------------------------------------------------------------
479
480   string FileReaderBase::BaseImpl::TagPath::asString()
481   {
482     ostringstream s;
483
484     s << "(";
485
486     if (depth())
487     {
488       TagList::const_iterator p = path.begin();
489       s << *p;
490       ++p;
491
492       for (; p != path.end(); ++p)
493         s << "," << *p;
494     }
495     else
496       s << "empty";
497
498     s << ")";
499
500     return s.str();
501   }
502
503
504     } // ns yum
505   } // ns parser
506 } // ns zypp
507
508 // vim: set ts=2 sts=2 sw=2 et ai: