HistoryLogReader: new HistoryLogData based API for parsing the new history file entri...
[platform/upstream/libzypp.git] / zypp / HistoryLogData.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9
10 /** \file zypp/HistoryLogData.cc
11  *
12  */
13 #include <sstream>
14
15 #include "zypp/base/PtrTypes.h"
16 #include "zypp/base/String.h"
17 #include "zypp/base/Logger.h"
18 #include "zypp/parser/ParseException.h"
19
20 #include "zypp/HistoryLogData.h"
21
22 using namespace std;
23
24 ///////////////////////////////////////////////////////////////////
25 namespace zypp
26 {
27   using parser::ParseException;
28
29   ///////////////////////////////////////////////////////////////////
30   //
31   //    class HistoryActionID
32   //
33   ///////////////////////////////////////////////////////////////////
34
35   const HistoryActionID HistoryActionID::NONE                   (HistoryActionID::NONE_e);
36   const HistoryActionID HistoryActionID::INSTALL                (HistoryActionID::INSTALL_e);
37   const HistoryActionID HistoryActionID::REMOVE                 (HistoryActionID::REMOVE_e);
38   const HistoryActionID HistoryActionID::REPO_ADD               (HistoryActionID::REPO_ADD_e);
39   const HistoryActionID HistoryActionID::REPO_REMOVE            (HistoryActionID::REPO_REMOVE_e);
40   const HistoryActionID HistoryActionID::REPO_CHANGE_ALIAS      (HistoryActionID::REPO_CHANGE_ALIAS_e);
41   const HistoryActionID HistoryActionID::REPO_CHANGE_URL        (HistoryActionID::REPO_CHANGE_URL_e);
42
43   HistoryActionID::HistoryActionID(const std::string & strval_r)
44     : _id(parse(strval_r))
45   {}
46
47   HistoryActionID::ID HistoryActionID::parse( const std::string & strval_r )
48   {
49     typedef std::map<std::string,ID> MapType;
50     static MapType _table;
51     if ( _table.empty() )
52     {
53       // initialize it
54       _table["install"] = INSTALL_e;
55       _table["remove"]  = REMOVE_e;
56       _table["radd"]    = REPO_ADD_e;
57       _table["rremove"] = REPO_REMOVE_e;
58       _table["ralias"]  = REPO_CHANGE_ALIAS_e;
59       _table["rurl"]    = REPO_CHANGE_URL_e;
60       _table["NONE"]    = _table["none"] = NONE_e;
61     }
62
63     MapType::const_iterator it = _table.find( strval_r );
64     if ( it != _table.end() )
65       return it->second;
66     // else:
67     WAR << "Unknown history action ID '" + strval_r + "'" << endl;
68     return NONE_e;
69   }
70
71
72   const std::string & HistoryActionID::asString( bool pad ) const
73   {
74     typedef std::pair<std::string,std::string> PairType;
75     typedef std::map<ID, PairType> MapType;
76     static MapType _table;
77     if ( _table.empty() )
78     {
79       // initialize it                                     pad(7) (for now)
80       _table[INSTALL_e]           = PairType( "install" , "install" );
81       _table[REMOVE_e]            = PairType( "remove"  , "remove " );
82       _table[REPO_ADD_e]          = PairType( "radd"    , "radd   " );
83       _table[REPO_REMOVE_e]       = PairType( "rremove" , "rremove" );
84       _table[REPO_CHANGE_ALIAS_e] = PairType( "ralias"  , "ralias " );
85       _table[REPO_CHANGE_URL_e]   = PairType( "rurl"    , "rurl   " );
86       _table[NONE_e]              = PairType( "NONE"    , "NONE   " );
87     }
88
89     return( pad ? _table[_id].second : _table[_id].first );
90   }
91
92   std::ostream & operator << (std::ostream & str, const HistoryActionID & id)
93   { return str << id.asString(); }
94
95   ///////////////////////////////////////////////////////////////////
96
97   ///////////////////////////////////////////////////////////////////
98   //
99   //    class HistoryLogData::Impl
100   //
101   ///////////////////////////////////////////////////////////////////
102   class HistoryLogData::Impl
103   {
104   public:
105     Impl( FieldVector & fields_r, size_type expect_r )
106     {
107       _checkFields( fields_r, expect_r );
108       _field.swap( fields_r );
109       // For whatever reason writer is ' '-padding the action field
110       // but we don't want to modify the vector before we moved it.
111       _field[ACTION_INDEX] = str::trim( _field[ACTION_INDEX] );
112       _action = HistoryActionID( _field[ACTION_INDEX] );
113     }
114
115     Impl( FieldVector & fields_r, HistoryActionID action_r, size_type expect_r )
116     {
117       _checkFields( fields_r, expect_r );
118       // For whatever reason writer is ' '-padding the action field
119       // but we don't want to modify the vector before we moved it.
120       std::string trimmed( str::trim( fields_r[ACTION_INDEX] ) );
121       _action = HistoryActionID( trimmed );
122       if ( _action != action_r )
123       {
124         ZYPP_THROW( ParseException( str::form( "Bad action id. Got %s, expected %s.",
125                                                _action.asString().c_str(),
126                                                action_r.asString().c_str() ) ) );
127       }
128       _field.swap( fields_r );
129       // now adjust action field:
130       _field[ACTION_INDEX] = trimmed;
131     }
132
133     void _checkFields( const FieldVector & fields_r, size_type expect_r )
134     {
135       if ( expect_r < 2 )       // at least 2 fields (date and action) are required
136         expect_r = 2;
137       if ( fields_r.size() < expect_r )
138       {
139         ZYPP_THROW( ParseException( str::form( "Bad number of fields. Got %zd, expected at least %zd.",
140                                                fields_r.size(),
141                                                expect_r ) ) );
142       }
143       try
144       {
145         _date = Date( fields_r[DATE_INDEX], HISTORY_LOG_DATE_FORMAT );
146       }
147       catch ( const std::exception & excpt )
148       {
149         ZYPP_THROW( ParseException( excpt.what() ) );   // invalid date format
150       }
151       // _action handled later
152     }
153
154   public:
155     FieldVector         _field;
156     Date                _date;
157     HistoryActionID     _action;
158   };
159
160   ///////////////////////////////////////////////////////////////////
161   //
162   //    class HistoryLogData
163   //
164   ///////////////////////////////////////////////////////////////////
165
166   HistoryLogData::HistoryLogData( FieldVector & fields_r, size_type expect_r )
167   : _pimpl( new Impl( fields_r, expect_r ) )
168   {}
169
170   HistoryLogData::HistoryLogData( FieldVector & fields_r, HistoryActionID expectedId_r, size_type expect_r )
171   : _pimpl( new Impl( fields_r, expectedId_r, expect_r ) )
172   {}
173
174   HistoryLogData::~HistoryLogData()
175   {}
176
177   HistoryLogData::Ptr HistoryLogData::create( FieldVector & fields_r )
178   {
179     if ( fields_r.size() >= 2 )
180     {
181       // str::trim( _field[ACTION_INDEX] );
182       switch ( HistoryActionID( str::trim( fields_r[ACTION_INDEX] ) ).toEnum() )
183       {
184 #define OUTS(E,T) case HistoryActionID::E: return Ptr( new T( fields_r ) ); break;
185         OUTS( INSTALL_e,                HistoryLogDataInstall );
186         OUTS( REMOVE_e,                 HistoryLogDataRemove );
187         OUTS( REPO_ADD_e,               HistoryLogDataRepoAdd );
188         OUTS( REPO_REMOVE_e,            HistoryLogDataRepoRemove );
189         OUTS( REPO_CHANGE_ALIAS_e,      HistoryLogDataRepoAliasChange );
190         OUTS( REPO_CHANGE_URL_e,        HistoryLogDataRepoUrlChange );
191 #undef OUTS
192         // intentionally no default:
193         case HistoryActionID::NONE_e:
194           break;
195       }
196     }
197     // unknown action or invalid fields? Ctor will accept or throw.
198     return Ptr( new HistoryLogData( fields_r ) );
199   }
200
201   bool HistoryLogData::empty() const
202   { return _pimpl->_field.empty(); }
203
204   HistoryLogData::size_type HistoryLogData::size() const
205   { return _pimpl->_field.size(); }
206
207   HistoryLogData::const_iterator HistoryLogData::begin() const
208   { return _pimpl->_field.begin(); }
209
210   HistoryLogData::const_iterator HistoryLogData::end() const
211   { return _pimpl->_field.end(); }
212
213   const std::string & HistoryLogData::optionalAt( size_type idx_r ) const
214   {
215     static const std::string _empty;
216     return( idx_r < size() ? _pimpl->_field[idx_r] : _empty );
217   }
218
219   const std::string & HistoryLogData::at( size_type idx_r ) const
220   { return _pimpl->_field.at( idx_r ); }
221
222
223   Date HistoryLogData::date() const
224   { return _pimpl->_date; }
225
226   HistoryActionID HistoryLogData::action() const
227   { return _pimpl->_action; }
228
229
230   std::ostream & operator<<( std::ostream & str, const HistoryLogData & obj )
231   { return str << str::joinEscaped( obj.begin(), obj.end(), '|' ); }
232
233   ///////////////////////////////////////////////////////////////////
234   //    class HistoryLogDataInstall
235   ///////////////////////////////////////////////////////////////////
236     HistoryLogDataInstall::HistoryLogDataInstall( FieldVector & fields_r )
237     : HistoryLogData( fields_r )
238     {}
239     std::string HistoryLogDataInstall::name()           const { return optionalAt( NAME_INDEX ); }
240     Edition     HistoryLogDataInstall::edition()        const { return Edition( optionalAt( EDITION_INDEX ) ); }
241     Arch        HistoryLogDataInstall::arch()           const { return Arch( optionalAt( ARCH_INDEX ) ); }
242     std::string HistoryLogDataInstall::reqby()          const { return optionalAt( REQBY_INDEX ); }
243     std::string HistoryLogDataInstall::repoAlias()      const { return optionalAt( REPOALIAS_INDEX ); }
244     CheckSum    HistoryLogDataInstall::checksum()       const { return optionalAt( CHEKSUM_INDEX ); }
245     std::string HistoryLogDataInstall::userdata()       const { return optionalAt( USERDATA_INDEX ); }
246
247   ///////////////////////////////////////////////////////////////////
248   //    class HistoryLogDataRemove
249   ///////////////////////////////////////////////////////////////////
250     HistoryLogDataRemove::HistoryLogDataRemove( FieldVector & fields_r )
251     : HistoryLogData( fields_r )
252     {}
253     std::string HistoryLogDataRemove::name()            const { return optionalAt( NAME_INDEX ); }
254     Edition     HistoryLogDataRemove::edition()         const { return Edition( optionalAt( EDITION_INDEX ) ); }
255     Arch        HistoryLogDataRemove::arch()            const { return Arch( optionalAt( ARCH_INDEX ) ); }
256     std::string HistoryLogDataRemove::reqby()           const { return optionalAt( REQBY_INDEX ); }
257     std::string HistoryLogDataRemove::userdata()        const { return optionalAt( USERDATA_INDEX ); }
258
259   ///////////////////////////////////////////////////////////////////
260   //    class HistoryLogDataRepoAdd
261   ///////////////////////////////////////////////////////////////////
262     HistoryLogDataRepoAdd::HistoryLogDataRepoAdd( FieldVector & fields_r )
263     : HistoryLogData( fields_r )
264     {}
265     std::string HistoryLogDataRepoAdd::alias()          const { return optionalAt( ALIAS_INDEX ); }
266     Url         HistoryLogDataRepoAdd::url()            const { return optionalAt( URL_INDEX ); }
267     std::string HistoryLogDataRepoAdd::userdata()       const { return optionalAt( USERDATA_INDEX ); }
268
269   ///////////////////////////////////////////////////////////////////
270   //    class HistoryLogDataRepoRemove
271   ///////////////////////////////////////////////////////////////////
272     HistoryLogDataRepoRemove::HistoryLogDataRepoRemove( FieldVector & fields_r )
273     : HistoryLogData( fields_r )
274     {}
275     std::string HistoryLogDataRepoRemove::alias()       const { return optionalAt( ALIAS_INDEX ); }
276     std::string HistoryLogDataRepoRemove::userdata()    const { return optionalAt( USERDATA_INDEX ); }
277
278   ///////////////////////////////////////////////////////////////////
279   //    class HistoryLogDataRepoAliasChange
280   ///////////////////////////////////////////////////////////////////
281     HistoryLogDataRepoAliasChange::HistoryLogDataRepoAliasChange( FieldVector & fields_r )
282     : HistoryLogData( fields_r )
283     {}
284     std::string HistoryLogDataRepoAliasChange::oldAlias()       const { return optionalAt( OLDALIAS_INDEX ); }
285     std::string HistoryLogDataRepoAliasChange::newAlias()       const { return optionalAt( NEWALIAS_INDEX ); }
286     std::string HistoryLogDataRepoAliasChange::userdata()       const { return optionalAt( USERDATA_INDEX ); }
287
288   ///////////////////////////////////////////////////////////////////
289   //    class HistoryLogDataRepoUrlChange
290   ///////////////////////////////////////////////////////////////////
291     HistoryLogDataRepoUrlChange::HistoryLogDataRepoUrlChange( FieldVector & fields_r )
292     : HistoryLogData( fields_r )
293     {}
294     std::string HistoryLogDataRepoUrlChange::alias()    const { return optionalAt( ALIAS_INDEX ); }
295     Url         HistoryLogDataRepoUrlChange::newUrl()   const { return optionalAt( NEWURL_INDEX ); }
296     std::string HistoryLogDataRepoUrlChange::userdata() const { return optionalAt( USERDATA_INDEX ); }
297
298
299 #if defined(WITH_DEPRECATED_HISTORYITEM_API)
300   ///////////////////////////////////////////////////////////////////
301   /// \class HistoryItem
302   /// \deprecated Old unextensible \ref zypp::parser::HistoryLogReader data class.
303   /// They grant direct access to data members, so can not be extended
304   /// without losing binary compatibility.
305   ///////////////////////////////////////////////////////////////////
306   HistoryItem::HistoryItem(FieldVector & fields)
307   {
308     if (fields.size() <= 2)
309       ZYPP_THROW(ParseException(
310         str::form("Bad number of fields. Got %zd, expected more than %d.",
311           fields.size(), 2)));
312
313     date = Date(fields[0], HISTORY_LOG_DATE_FORMAT);
314     action = HistoryActionID(str::trim(fields[1]));
315   }
316
317   void HistoryItem::dumpTo(ostream & str) const
318   {
319     str << date.form(HISTORY_LOG_DATE_FORMAT) << "|" << action.asString();
320   }
321
322   ostream & operator<<(ostream & str, const HistoryItem & obj)
323   {
324     obj.dumpTo(str);
325     return str;
326   }
327
328
329   /////////////////////////////////////////////////////////////////////
330   //
331   // CLASS NAME: HistoryItemInstall (deprecated!)
332   //
333   /////////////////////////////////////////////////////////////////////
334
335   HistoryItemInstall::HistoryItemInstall(FieldVector & fields)
336     : HistoryItem(fields)
337   {
338     if (fields.size() < 8)
339       ZYPP_THROW(ParseException(
340         str::form("Bad number of fields. Got %zu, expected %u.",
341           fields.size(), 8)));
342
343     name      = fields[2];
344     edition   = Edition(fields[3]);
345     arch      = Arch(fields[4]);
346     reqby     = fields[5];
347     repoalias = fields[6];
348     checksum  = CheckSum::sha(fields[7]);
349   }
350
351   void HistoryItemInstall::dumpTo(ostream & str) const
352   {
353     HistoryItem::dumpTo(str);
354     str << "|"
355       << name << "|"
356       << edition << "|"
357       << arch << "|"
358       << reqby << "|"
359       << repoalias << "|"
360       << checksum;
361   }
362
363   ostream & operator<<(ostream & str, const HistoryItemInstall & obj)
364   {
365     obj.dumpTo(str);
366     return str;
367   }
368
369
370   /////////////////////////////////////////////////////////////////////
371   //
372   // CLASS NAME: HistoryItemRemove (deprecated!)
373   //
374   /////////////////////////////////////////////////////////////////////
375
376   HistoryItemRemove::HistoryItemRemove(FieldVector & fields)
377     : HistoryItem(fields)
378   {
379     if (fields.size() < 6)
380       ZYPP_THROW(ParseException(
381         str::form("Bad number of fields. Got %zu, expected %u.",
382           fields.size(), 6)));
383
384     name      = fields[2];
385     edition   = Edition(fields[3]);
386     arch      = Arch(fields[4]);
387     reqby     = fields[5];
388   }
389
390   void HistoryItemRemove::dumpTo(ostream & str) const
391   {
392     HistoryItem::dumpTo(str);
393     str << "|"
394       << name << "|"
395       << edition << "|"
396       << arch << "|"
397       << reqby;
398   }
399
400   ostream & operator<<(ostream & str, const HistoryItemRemove & obj)
401   {
402     obj.dumpTo(str);
403     return str;
404   }
405
406
407   /////////////////////////////////////////////////////////////////////
408   //
409   // CLASS NAME: HistoryItemRepoAdd (deprecated!)
410   //
411   /////////////////////////////////////////////////////////////////////
412
413   HistoryItemRepoAdd::HistoryItemRepoAdd(FieldVector & fields)
414     : HistoryItem(fields)
415   {
416     if (fields.size() < 4)
417       ZYPP_THROW(ParseException(
418         str::form("Bad number of fields. Got %zu, expected %u.",
419           fields.size(), 4)));
420
421     alias = fields[2];
422     url = Url(fields[3]);
423   }
424
425   void HistoryItemRepoAdd::dumpTo(ostream & str) const
426   {
427     HistoryItem::dumpTo(str);
428     str << "|"
429       << alias << "|"
430       << url;
431   }
432
433   ostream & operator<<(ostream & str, const HistoryItemRepoAdd & obj)
434   {
435     obj.dumpTo(str);
436     return str;
437   }
438
439
440   /////////////////////////////////////////////////////////////////////
441   //
442   // CLASS NAME: HistoryItemRepoRemove (deprecated!)
443   //
444   /////////////////////////////////////////////////////////////////////
445
446   HistoryItemRepoRemove::HistoryItemRepoRemove(FieldVector & fields)
447     : HistoryItem(fields)
448   {
449     if (fields.size() < 3)
450       ZYPP_THROW(ParseException(
451         str::form("Bad number of fields. Got %zu, expected %u.",
452           fields.size(), 3)));
453
454     alias = fields[2];
455   }
456
457   void HistoryItemRepoRemove::dumpTo(ostream & str) const
458   {
459     HistoryItem::dumpTo(str);
460     str << "|" << alias;
461   }
462
463   ostream & operator<<(ostream & str, const HistoryItemRepoRemove & obj)
464   {
465     obj.dumpTo(str);
466     return str;
467   }
468
469
470   /////////////////////////////////////////////////////////////////////
471   //
472   // CLASS NAME: HistoryItemRepoAliasChange (deprecated!)
473   //
474   /////////////////////////////////////////////////////////////////////
475
476   HistoryItemRepoAliasChange::HistoryItemRepoAliasChange(FieldVector & fields)
477     : HistoryItem(fields)
478   {
479     if (fields.size() < 4)
480       ZYPP_THROW(ParseException(
481         str::form("Bad number of fields. Got %zu, expected %u.",
482           fields.size(), 4)));
483
484     oldalias = fields[2];
485     newalias = fields[3];
486   }
487
488   void HistoryItemRepoAliasChange::dumpTo(ostream & str) const
489   {
490     HistoryItem::dumpTo(str);
491     str << "|" << oldalias << "|" << newalias;
492   }
493
494   ostream & operator<<(ostream & str, const HistoryItemRepoAliasChange & obj)
495   {
496     obj.dumpTo(str);
497     return str;
498   }
499
500
501   /////////////////////////////////////////////////////////////////////
502   //
503   // CLASS NAME: HistoryItemRepoUrlChange (deprecated!)
504   //
505   /////////////////////////////////////////////////////////////////////
506
507   HistoryItemRepoUrlChange::HistoryItemRepoUrlChange(FieldVector & fields)
508     : HistoryItem(fields)
509   {
510     if (fields.size() < 4)
511       ZYPP_THROW(ParseException(
512         str::form("Bad number of fields. Got %zu, expected %u.",
513           fields.size(), 4)));
514
515     alias = fields[2];
516     newurl = Url(fields[3]);
517   }
518
519   void HistoryItemRepoUrlChange::dumpTo(ostream & str) const
520   {
521     HistoryItem::dumpTo(str);
522     str << "|" << alias << "|" << newurl;
523   }
524
525   ostream & operator<<(ostream & str, const HistoryItemRepoUrlChange & obj)
526   {
527     obj.dumpTo(str);
528     return str;
529   }
530 #endif // WITH_DEPRECATED_HISTORYITEM_API
531
532 } // namespace zypp
533 ///////////////////////////////////////////////////////////////////