- one more alias to escape
[platform/upstream/libzypp.git] / zypp / HistoryLog.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/target/HistoryLog.cc
10  *
11  */
12 #include <iostream>
13 #include <fstream>
14 #include <unistd.h>
15
16 #include "zypp/ZConfig.h"
17 #include "zypp/base/String.h"
18 #include "zypp/base/Logger.h"
19
20 #include "zypp/PathInfo.h"
21 #include "zypp/Date.h"
22
23 #include "zypp/PoolItem.h"
24 #include "zypp/Package.h"
25 #include "zypp/RepoInfo.h"
26
27 #include "zypp/HistoryLog.h"
28
29 using std::endl;
30 using std::string;
31
32 namespace
33 {
34   inline string timestamp()
35   { return zypp::Date::now().form( "%Y-%m-%d %H:%M:%S" ); }
36
37   inline string userAtHostname()
38   {
39     static char buf[256];
40     string result;
41     char * tmp = ::cuserid(buf); 
42     if (tmp)
43     {
44       result = string(tmp);
45       if (!::gethostname(buf, 255))
46         result += "@" + string(buf);
47     }
48     return result;
49   }
50 }
51
52 namespace zypp
53 {
54   ///////////////////////////////////////////////////////////////////
55   //
56   //    CLASS NAME : HistoryActionID
57   //
58   ///////////////////////////////////////////////////////////////////
59
60   static std::map<std::string,HistoryActionID::ID> _table;
61
62   const HistoryActionID HistoryActionID::NONE(HistoryActionID::NONE_e);
63   const HistoryActionID HistoryActionID::INSTALL(HistoryActionID::INSTALL_e);
64   const HistoryActionID HistoryActionID::REMOVE(HistoryActionID::REMOVE_e);
65   const HistoryActionID HistoryActionID::REPO_ADD(HistoryActionID::REPO_ADD_e);
66   const HistoryActionID HistoryActionID::REPO_REMOVE(HistoryActionID::REPO_REMOVE_e);
67   const HistoryActionID HistoryActionID::REPO_CHANGE_ALIAS(HistoryActionID::REPO_CHANGE_ALIAS_e);
68   const HistoryActionID HistoryActionID::REPO_CHANGE_URL(HistoryActionID::REPO_CHANGE_URL_e);
69
70   HistoryActionID::HistoryActionID(const std::string & strval_r)
71     : _id(parse(strval_r))
72   {}
73
74   HistoryActionID::ID HistoryActionID::parse(const std::string & strval_r)
75   {
76     if (_table.empty())
77     {
78       // initialize it
79       _table["install"] = INSTALL_e;
80       _table["remove"]  = REMOVE_e;
81       _table["radd"]    = REPO_ADD_e;
82       _table["rremove"] = REPO_REMOVE_e;
83       _table["ralias"]  = REPO_CHANGE_ALIAS_e;
84       _table["rurl"]    = REPO_CHANGE_URL_e;
85       _table["NONE"] = _table["none"] = HistoryActionID::NONE_e;
86     }
87
88     std::map<std::string,HistoryActionID::ID>::const_iterator it =
89       _table.find(strval_r);
90
91     if (it == _table.end())
92       WAR << "Unknown history action ID '" + strval_r + "'";
93
94     return it->second;
95   }
96
97
98   const std::string & HistoryActionID::asString(bool pad) const
99   {
100     static std::map<ID, std::string> _table;
101     if ( _table.empty() )
102     {
103       // initialize it
104       _table[INSTALL_e]           = "install";
105       _table[REMOVE_e]            = "remove";
106       _table[REPO_ADD_e]          = "radd";
107       _table[REPO_REMOVE_e]       = "rremove";
108       _table[REPO_CHANGE_ALIAS_e] = "ralias";
109       _table[REPO_CHANGE_URL_e]   = "rurl";
110       _table[NONE_e]              = "NONE";
111     }
112     // add spaces so that the size of the returned string is always 7 (for now)
113     if (pad)
114       return _table[_id].append(7 - _table[_id].size(), ' ');
115     return _table[_id];
116   }
117
118   std::ostream & operator << (std::ostream & str, const HistoryActionID & id)
119   { return str << id.asString(); }
120
121   ///////////////////////////////////////////////////////////////////
122
123   ///////////////////////////////////////////////////////////////////
124   //
125   //    CLASS NAME : HistoryLog
126   //
127   ///////////////////////////////////////////////////////////////////
128
129   Pathname HistoryLog::_fname(ZConfig::instance().historyLogFile());
130   std::ofstream HistoryLog::_log;
131   unsigned HistoryLog::_refcnt = 0;
132   const char HistoryLog::_sep = '|';
133
134   ///////////////////////////////////////////////////////////////////
135
136   HistoryLog::HistoryLog( const Pathname & rootdir )
137   {
138     refUp();
139     if (!rootdir.empty() && rootdir.absolute())
140       _fname = rootdir / ZConfig::instance().historyLogFile();
141   }
142
143   void HistoryLog::openLog()
144   {
145     if ( !_fname.empty() )
146     {
147       _log.clear();
148       _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app );
149       if( !_log )
150         ERR << "Could not open logfile '" << _fname << "'" << endl;
151     }
152   }
153
154   void HistoryLog::closeLog()
155   {
156     _log.clear();
157     _log.close();
158   }
159
160   void HistoryLog::refUp()
161   {
162     if ( !_refcnt )
163       openLog();
164     ++_refcnt;
165   }
166
167   void HistoryLog::refDown()
168   {
169     --_refcnt;
170     if ( !_refcnt )
171       closeLog();
172   }
173
174
175   void HistoryLog::setRoot( const Pathname & rootdir )
176   {
177     if (rootdir.empty() || !rootdir.absolute())
178       return;
179
180     if ( _refcnt )
181       closeLog();
182
183     _fname = rootdir / "/var/log/zypp/history";
184     filesystem::assert_dir( _fname.dirname() );
185     MIL << "installation log file " << _fname << endl;
186
187     if ( _refcnt )
188       openLog();
189   }
190
191
192   const Pathname & HistoryLog::fname()
193   { return _fname; }
194
195   /////////////////////////////////////////////////////////////////////////
196
197   void HistoryLog::comment( const string & comment, bool timestamp )
198   {
199     if (comment.empty())
200       return;
201
202     _log << "# ";
203     if ( timestamp )
204       _log << ::timestamp() << " ";
205
206     const char * s = comment.c_str();
207     const char * c = s;
208     unsigned size = comment.size();
209
210     // ignore the last newline
211     if (comment[size-1] == '\n')
212       --size;
213
214     for ( unsigned i = 0; i < size; ++i, ++c )
215       if ( *c == '\n' )
216       {
217         _log << string( s, c + 1 - s ) << "# ";
218         s = c + 1;
219       }
220
221     if ( s < c )
222       _log << std::string( s, c-s );
223
224     _log << endl;
225   }
226
227   /////////////////////////////////////////////////////////////////////////
228   
229   void HistoryLog::install( const PoolItem & pi )
230   {
231     const Package::constPtr p = asKind<Package>(pi.resolvable());
232     if (!p)
233       return;
234
235     _log
236       << timestamp()                                   // 1 timestamp
237       << _sep << HistoryActionID::INSTALL.asString(true) // 2 action
238       << _sep << p->name()                             // 3 name
239       << _sep << p->edition()                          // 4 evr
240       << _sep << p->arch();                            // 5 arch
241
242     if (pi.status().isByUser())
243       _log << _sep << userAtHostname();                // 6 reqested by
244     //else if (pi.status().isByApplHigh() || pi.status().isByApplLow())
245     //  _log << _sep << "appl";
246     else
247       _log << _sep;
248
249     _log
250       << _sep << p->repoInfo().alias()                 // 7 repo alias
251       << _sep << p->checksum().checksum();             // 8 checksum
252
253     _log << endl; 
254
255     //_log << pi << endl;
256   }
257
258
259   void HistoryLog::remove( const PoolItem & pi )
260   {
261     const Package::constPtr p = asKind<Package>(pi.resolvable());
262     if (!p)
263       return;
264
265     _log
266       << timestamp()                                   // 1 timestamp
267       << _sep << HistoryActionID::REMOVE.asString(true) // 2 action
268       << _sep << p->name()                             // 3 name
269       << _sep << p->edition()                          // 4 evr
270       << _sep << p->arch();                            // 5 arch
271
272     if (pi.status().isByUser())
273       _log << _sep << userAtHostname();                // 6 reqested by
274     //else if (pi.status().isByApplHigh() || pi.status().isByApplLow())
275     //  _log << _sep << "appl";
276     else
277       _log << _sep;
278
279     // we don't have checksum in rpm db
280     //  << _sep << p->checksum().checksum();           // x checksum
281
282     _log << endl; 
283
284     //_log << pi << endl;
285   }
286
287   /////////////////////////////////////////////////////////////////////////
288
289   void HistoryLog::addRepository(const RepoInfo & repo)
290   {
291     _log
292       << timestamp()                                   // 1 timestamp
293       << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action 
294       << _sep << str::escape(repo.alias(), _sep)       // 3 alias
295       // what about the rest of the URLs??
296       << _sep << *repo.baseUrlsBegin()                 // 4 primary URL
297       << endl;
298   }
299
300
301   void HistoryLog::removeRepository(const RepoInfo & repo)
302   {
303     _log
304       << timestamp()                                   // 1 timestamp
305       << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action 
306       << _sep << str::escape(repo.alias(), _sep)       // 3 alias
307       << endl;
308   }
309
310
311   void HistoryLog::modifyRepository(
312       const RepoInfo & oldrepo, const RepoInfo & newrepo)
313   {
314     if (oldrepo.alias() != newrepo.alias())
315     {
316       _log
317         << timestamp()                                    // 1 timestamp
318         << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true) // 2 action
319         << _sep << str::escape(oldrepo.alias(), _sep)     // 3 old alias
320         << _sep << str::escape(newrepo.alias(), _sep);    // 4 new alias
321     }
322     
323     if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
324     {
325       _log
326         << timestamp()                                    // 1 timestamp
327         << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action
328         << _sep << str::escape(oldrepo.alias(), _sep)              // 3 old url
329         << _sep << *newrepo.baseUrlsBegin();                       // 4 new url
330     }
331   }
332
333   ///////////////////////////////////////////////////////////////////
334
335 } // namespace zypp