Also parse <product> tag from .prod files <upgrade> section.
[platform/upstream/libzypp.git] / zypp / parser / ProductFileReader.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/parser/ProductFileReader.cc
10  *
11 */
12 #include <iostream>
13 #include "zypp/base/Logger.h"
14 #include "zypp/base/Exception.h"
15 #include "zypp/base/Functional.h"
16
17 #include "zypp/PathInfo.h"
18
19 #include "zypp/parser/ProductFileReader.h"
20 #include "zypp/parser/xml/ParseDef.h"
21 #include "zypp/parser/xml/ParseDefConsume.h"
22 #include "zypp/parser/xml/Reader.h"
23
24 using std::endl;
25
26 ///////////////////////////////////////////////////////////////////
27 namespace zypp
28 { /////////////////////////////////////////////////////////////////
29   ///////////////////////////////////////////////////////////////////
30   namespace parser
31   { /////////////////////////////////////////////////////////////////
32
33     /////////////////////////////////////////////////////////////////
34     //
35     // class ProductFileData::Upgrade
36     //
37     /////////////////////////////////////////////////////////////////
38
39     struct ProductFileData::Upgrade::Impl
40     {
41       std::string                 _name;
42       std::string                 _summary;
43       std::string                 _repository;
44       std::string                 _product;
45       DefaultIntegral<bool,false> _notify;
46       std::string                 _status;
47     };
48
49     ProductFileData::Upgrade::Upgrade( Impl * allocated_r )
50       : _pimpl( allocated_r ? allocated_r : new Impl )
51     {}
52
53     std::string ProductFileData::Upgrade::name()       const { return _pimpl->_name; }
54     std::string ProductFileData::Upgrade::summary()    const { return _pimpl->_summary; }
55     std::string ProductFileData::Upgrade::repository() const { return _pimpl->_repository; }
56     std::string ProductFileData::Upgrade::product()    const { return _pimpl->_product; }
57     bool        ProductFileData::Upgrade::notify()     const { return _pimpl->_notify; }
58     std::string ProductFileData::Upgrade::status()     const { return _pimpl->_status; }
59
60     /////////////////////////////////////////////////////////////////
61     //
62     // class ProductFileData
63     //
64     /////////////////////////////////////////////////////////////////
65
66     struct ProductFileData::Impl
67     {
68       IdString    _vendor;
69       IdString    _name;
70       Edition     _edition;
71       Arch        _arch;
72
73       std::string _productline;
74       std::string _registerTarget;
75       std::string _registerRelease;
76
77       std::string _updaterepokey;
78
79       Upgrades    _upgrades;
80     };
81
82     ProductFileData::ProductFileData( Impl * allocated_r )
83       : _pimpl( allocated_r ? allocated_r : new Impl )
84     {}
85
86     IdString    ProductFileData::vendor()  const { return _pimpl->_vendor; }
87     IdString    ProductFileData::name()    const { return _pimpl->_name; }
88     Edition     ProductFileData::edition() const { return _pimpl->_edition; }
89     Arch        ProductFileData::arch()    const { return _pimpl->_arch; }
90
91     std::string ProductFileData::productline()     const { return _pimpl->_productline; }
92     std::string ProductFileData::registerTarget()  const { return _pimpl->_registerTarget; }
93     std::string ProductFileData::registerRelease() const { return _pimpl->_registerRelease; }
94
95     std::string ProductFileData::updaterepokey() const { return _pimpl->_updaterepokey; }
96
97     const ProductFileData::Upgrades & ProductFileData::upgrades() const { return _pimpl->_upgrades; }
98
99     std::ostream & operator<<( std::ostream & str, const ProductFileData & obj )
100     {
101       str << str::form( "|product|%s|%s|%s|%s|",
102                         obj.name().c_str(),
103                         obj.edition().c_str(),
104                         obj.arch().c_str(),
105                         obj.vendor().c_str() );
106       if ( ! obj.upgrades().empty() )
107       {
108         for_( it, obj.upgrades().begin(), obj.upgrades().end() )
109           str << endl << "    " << *it;
110       }
111       return str;
112     }
113
114     std::ostream & operator<<( std::ostream & str, const ProductFileData::Upgrade & obj )
115     {
116       str << str::form( "|upgrade|%s|%s|%s|%s|%s|",
117                         obj.name().c_str(),
118                         obj.repository().c_str(),
119                         obj.product().c_str(),
120                         obj.status().c_str(),
121                         (obj.notify() ? "notify" : "noNotify") );
122       return str;
123     }
124     /////////////////////////////////////////////////////////////////
125     //
126     // class ProductFileReader
127     //
128     /////////////////////////////////////////////////////////////////
129
130     struct ProductNode : public xml::ParseDef
131     {
132       ProductNode( ProductFileData::Impl & pdata_r )
133         : ParseDef( "product", MANDTAORY )
134         , _pdata( pdata_r )
135       {
136         (*this)
137             ("vendor",        OPTIONAL,   xml::parseDefAssign( _pdata._vendor ) )
138             ("name",          MANDTAORY,  xml::parseDefAssign( _pdata._name ) )
139             ("version",       MANDTAORY,  xml::parseDefAssign( _version ) )
140             ("release",       MANDTAORY,  xml::parseDefAssign( _release ) )
141             ("arch",          MANDTAORY,  xml::parseDefAssign( _pdata._arch ) )
142             ("productline",   OPTIONAL,   xml::parseDefAssign( _pdata._productline ) )
143             ("register",      OPTIONAL)
144             ("updaterepokey", OPTIONAL,   xml::parseDefAssign( _pdata._updaterepokey ) )
145             ("upgrades",      OPTIONAL)
146             ;
147
148         (*this)["register"]
149             ("target",        OPTIONAL,   xml::parseDefAssign( _pdata._registerTarget ) )
150             ("release",       OPTIONAL,   xml::parseDefAssign( _pdata._registerRelease ) )
151             ;
152
153         (*this)["upgrades"]
154             ("upgrade",       MULTIPLE_OPTIONAL, xml::parseDefAssign()
155                                                  >> bind( &ProductNode::doneUpgrade, this, _1 ))
156             ;
157
158         (*this)["upgrades"]["upgrade"]
159             ("name",          OPTIONAL,   xml::parseDefAssign( _upgrade._name ) )
160             ("summary",       OPTIONAL,   xml::parseDefAssign( _upgrade._summary ) )
161             ("repository",    OPTIONAL,   xml::parseDefAssign( _upgrade._repository ) )
162             ("product",       OPTIONAL,   xml::parseDefAssign( _upgrade._product ) )
163             ("notify",        OPTIONAL,   xml::parseDefAssign( _upgrade._notify ) )
164             ("status",        OPTIONAL,   xml::parseDefAssign( _upgrade._status ) )
165             ;
166
167         // </product> callback to build edition.
168         setConsumer( xml::parseDefAssign() >> bind( &ProductNode::done, this, _1 ) );
169         // xml::ParseDef::_debug = true;
170       }
171
172       /** collect _upgrade */
173       void doneUpgrade( const xml::Node & _node )
174       {
175         ProductFileData::Upgrade cdata( new ProductFileData::Upgrade::Impl( _upgrade ) );
176         _pdata._upgrades.push_back( cdata );
177         _upgrade = ProductFileData::Upgrade::Impl();
178       }
179
180       /** finaly */
181       void done( const xml::Node & _node )
182       {
183         _pdata._edition = Edition( _version, _release );
184       }
185
186       private:
187         ProductFileData::Impl & _pdata;
188
189         std::string             _version;
190         std::string             _release;
191
192         ProductFileData::Upgrade::Impl _upgrade;
193     };
194
195     bool ProductFileReader::parse( const InputStream & input_r ) const
196     {
197       MIL << "+++" << input_r << endl;
198       bool ret = true;
199
200       ProductFileData::Impl * pdataImpl = 0;
201       ProductFileData pdata( (pdataImpl = new ProductFileData::Impl) );
202
203       try
204       {
205         xml::Reader reader( input_r );
206         ProductNode rootNode( *pdataImpl );
207         rootNode.take( reader );
208
209       }
210       catch ( const Exception & err )
211       {
212         // parse error
213         ERR << err << endl;
214         ERR << "---" << ret << " - " << input_r << endl;
215         return ret;
216       }
217
218       if ( _consumer )
219       {
220         ret = _consumer( pdata );
221       }
222
223       MIL << "---" << ret << " - " << input_r << endl;
224       return ret;
225     }
226
227     /////////////////////////////////////////////////////////////////
228
229     bool ProductFileReader::scanDir( const Consumer & consumer_r, const Pathname & dir_r )
230     {
231       std::list<Pathname> retlist;
232       int res = filesystem::readdir( retlist, dir_r, /*dots*/false );
233       if ( res != 0 )
234       {
235         WAR << "scanDir " << dir_r << " failed (" << res << ")" << endl;
236         return true;
237       }
238
239       ProductFileReader reader( consumer_r );
240       for_( it, retlist.begin(), retlist.end() )
241       {
242         if ( PathInfo( *it, PathInfo::LSTAT ).isFile() && ! reader.parse( *it ) )
243         {
244           return false; // consumer_r request to stop parsing.
245         }
246       }
247       return true;
248     }
249
250     ProductFileData ProductFileReader::scanFile( const Pathname & file_r )
251     {
252       if ( ! PathInfo( file_r ).isFile() )
253       {
254         WAR << "scanFile " << PathInfo( file_r ) << " is not a file." << endl;
255         return ProductFileData();
256       }
257
258       ProductFileData ret;
259       ProductFileReader reader( functor::getFirst( ret ), file_r );
260       return ret;
261    }
262
263     /////////////////////////////////////////////////////////////////
264   } // namespace parser
265   ///////////////////////////////////////////////////////////////////
266   /////////////////////////////////////////////////////////////////
267 } // namespace zypp
268 ///////////////////////////////////////////////////////////////////