Remove obsolete ResStatus bits.
[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 #include "zypp/HistoryLogData.h"
29
30 using std::endl;
31 using std::string;
32
33 namespace
34 {
35   inline string timestamp()
36   { return zypp::Date::now().form( HISTORY_LOG_DATE_FORMAT ); }
37
38   inline string userAtHostname()
39   {
40     static char buf[256];
41     string result;
42     char * tmp = ::cuserid(buf);
43     if (tmp)
44     {
45       result = string(tmp);
46       if (!::gethostname(buf, 255))
47         result += "@" + string(buf);
48     }
49     return result;
50   }
51
52   static std::string pidAndAppname()
53   {
54     static std::string _val;
55     if ( _val.empty() )
56     {
57       pid_t mypid = getpid();
58       zypp::Pathname p( "/proc/"+zypp::str::numstring(mypid)+"/exe" );
59       zypp::Pathname myname( zypp::filesystem::readlink( p ) );
60
61       _val += zypp::str::numstring(mypid);
62       _val += ":";
63       _val += myname.basename();
64     }
65     return _val;
66   }
67 }
68
69 namespace zypp
70 {
71   namespace
72   {
73     const char          _sep = '|';
74     std::ofstream       _log;
75     unsigned            _refcnt = 0;
76     Pathname            _fname;
77
78     inline void openLog()
79     {
80       if ( _fname.empty() )
81         _fname = ZConfig::instance().historyLogFile();
82
83       _log.clear();
84       _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app );
85       if( !_log )
86         ERR << "Could not open logfile '" << _fname << "'" << endl;
87     }
88
89     inline void closeLog()
90     {
91       _log.clear();
92       _log.close();
93     }
94
95     inline void refUp()
96     {
97       if ( !_refcnt )
98         openLog();
99       ++_refcnt;
100     }
101
102     inline void refDown()
103     {
104       --_refcnt;
105       if ( !_refcnt )
106         closeLog();
107     }
108   }
109
110   ///////////////////////////////////////////////////////////////////
111   //
112   //    CLASS NAME : HistoryLog
113   //
114   ///////////////////////////////////////////////////////////////////
115
116   HistoryLog::HistoryLog( const Pathname & rootdir )
117   {
118     setRoot( rootdir );
119     refUp();
120   }
121
122   HistoryLog::~HistoryLog()
123   {
124     refDown();
125   }
126
127   void HistoryLog::setRoot( const Pathname & rootdir )
128   {
129     if ( ! rootdir.absolute() )
130       return;
131
132     if ( _refcnt )
133       closeLog();
134
135     _fname = rootdir / ZConfig::instance().historyLogFile();
136     filesystem::assert_dir( _fname.dirname() );
137     MIL << "installation log file " << _fname << endl;
138
139     if ( _refcnt )
140       openLog();
141   }
142
143   const Pathname & HistoryLog::fname()
144   {
145     if ( _fname.empty() )
146       _fname = ZConfig::instance().historyLogFile();
147     return _fname;
148   }
149
150   /////////////////////////////////////////////////////////////////////////
151
152   void HistoryLog::comment( const string & comment, bool timestamp )
153   {
154     if (comment.empty())
155       return;
156
157     _log << "# ";
158     if ( timestamp )
159       _log << ::timestamp() << " ";
160
161     const char * s = comment.c_str();
162     const char * c = s;
163     unsigned size = comment.size();
164
165     // ignore the last newline
166     if (comment[size-1] == '\n')
167       --size;
168
169     for ( unsigned i = 0; i < size; ++i, ++c )
170       if ( *c == '\n' )
171       {
172         _log << string( s, c + 1 - s ) << "# ";
173         s = c + 1;
174       }
175
176     if ( s < c )
177       _log << std::string( s, c-s );
178
179     _log << endl;
180   }
181
182   /////////////////////////////////////////////////////////////////////////
183
184   void HistoryLog::install( const PoolItem & pi )
185   {
186     const Package::constPtr p = asKind<Package>(pi.resolvable());
187     if (!p)
188       return;
189
190     _log
191       << timestamp()                                   // 1 timestamp
192       << _sep << HistoryActionID::INSTALL.asString(true) // 2 action
193       << _sep << p->name()                             // 3 name
194       << _sep << p->edition()                          // 4 evr
195       << _sep << p->arch();                            // 5 arch
196
197     // ApplLow is what the solver selected on behalf of the user.
198     if (pi.status().isByUser() || pi.status().isByApplLow() )
199       _log << _sep << userAtHostname();                // 6 reqested by
200     else if (pi.status().isByApplHigh())
201       _log << _sep << pidAndAppname();
202     else
203       _log << _sep;
204
205     _log
206       << _sep << p->repoInfo().alias()                 // 7 repo alias
207       << _sep << p->checksum().checksum();             // 8 checksum
208
209     _log << endl;
210
211     //_log << pi << endl;
212   }
213
214
215   void HistoryLog::remove( const PoolItem & pi )
216   {
217     const Package::constPtr p = asKind<Package>(pi.resolvable());
218     if (!p)
219       return;
220
221     _log
222       << timestamp()                                   // 1 timestamp
223       << _sep << HistoryActionID::REMOVE.asString(true) // 2 action
224       << _sep << p->name()                             // 3 name
225       << _sep << p->edition()                          // 4 evr
226       << _sep << p->arch();                            // 5 arch
227
228     // ApplLow is what the solver selected on behalf of the user.
229     if ( pi.status().isByUser() || pi.status().isByApplLow() )
230       _log << _sep << userAtHostname();                // 6 reqested by
231     else if (pi.status().isByApplHigh())
232       _log << _sep << pidAndAppname();
233     else
234       _log << _sep;
235
236     // we don't have checksum in rpm db
237     //  << _sep << p->checksum().checksum();           // x checksum
238
239     _log << endl;
240
241     //_log << pi << endl;
242   }
243
244   /////////////////////////////////////////////////////////////////////////
245
246   void HistoryLog::addRepository(const RepoInfo & repo)
247   {
248     _log
249       << timestamp()                                   // 1 timestamp
250       << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action
251       << _sep << str::escape(repo.alias(), _sep)       // 3 alias
252       // what about the rest of the URLs??
253       << _sep << *repo.baseUrlsBegin()                 // 4 primary URL
254       << endl;
255   }
256
257
258   void HistoryLog::removeRepository(const RepoInfo & repo)
259   {
260     _log
261       << timestamp()                                   // 1 timestamp
262       << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action
263       << _sep << str::escape(repo.alias(), _sep)       // 3 alias
264       << endl;
265   }
266
267
268   void HistoryLog::modifyRepository(
269       const RepoInfo & oldrepo, const RepoInfo & newrepo)
270   {
271     if (oldrepo.alias() != newrepo.alias())
272     {
273       _log
274         << timestamp()                                    // 1 timestamp
275         << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true) // 2 action
276         << _sep << str::escape(oldrepo.alias(), _sep)     // 3 old alias
277         << _sep << str::escape(newrepo.alias(), _sep)     // 4 new alias
278         << endl;
279     }
280
281     if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
282     {
283       _log
284         << timestamp()                                             //1 timestamp
285         << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action
286         << _sep << str::escape(oldrepo.alias(), _sep)              // 3 old url
287         << _sep << *newrepo.baseUrlsBegin()                        // 4 new url
288         << endl;
289     }
290   }
291
292   ///////////////////////////////////////////////////////////////////
293
294 } // namespace zypp