fixup Fix to build with libxml 2.12.x (fixes #505)
[platform/upstream/libzypp.git] / zypp / HistoryLog.cc
index 447569c..985fa2d 100644 (file)
 #include <fstream>
 #include <unistd.h>
 
-#include "zypp/ZConfig.h"
-#include "zypp/base/String.h"
-#include "zypp/base/Logger.h"
+#include <zypp/ZConfig.h>
+#include <zypp/base/String.h>
+#include <zypp/base/Logger.h>
+#include <zypp/base/IOStream.h>
 
-#include "zypp/PathInfo.h"
-#include "zypp/Date.h"
+#include <zypp/PathInfo.h>
+#include <zypp/Date.h>
 
-#include "zypp/PoolItem.h"
-#include "zypp/Package.h"
-#include "zypp/RepoInfo.h"
+#include <zypp/PoolItem.h>
+#include <zypp/Package.h>
+#include <zypp/RepoInfo.h>
 
-#include "zypp/HistoryLog.h"
+#include <zypp/HistoryLog.h>
+#include <zypp/HistoryLogData.h>
 
 using std::endl;
 using std::string;
 
-namespace
+namespace zypp
 {
-  inline string timestamp()
-  { return zypp::Date::now().form( "%Y-%m-%d %H:%M:%S" ); }
-
-  inline string userAtHostname()
+  namespace
   {
-    static char buf[256];
-    string result;
-    char * tmp = ::cuserid(buf); 
-    if (tmp)
+    inline string timestamp()
+    { return zypp::Date::now().form( HISTORY_LOG_DATE_FORMAT ); }
+
+    inline string userAtHostname()
     {
-      result = string(tmp);
-      if (!::gethostname(buf, 255))
-        result += "@" + string(buf);
+      static char buf[256];
+      string result;
+      char * tmp = ::cuserid(buf);
+      if (tmp)
+      {
+       result = string(tmp);
+       if (!::gethostname(buf, 255))
+         result += "@" + string(buf);
+      }
+      return result;
     }
-    return result;
-  }
-}
 
-namespace zypp
-{
-  ///////////////////////////////////////////////////////////////////
-  //
-  //    CLASS NAME : HistoryActionID
-  //
-  ///////////////////////////////////////////////////////////////////
-
-  static std::map<std::string,HistoryActionID::ID> _table;
-
-  const HistoryActionID HistoryActionID::NONE(HistoryActionID::NONE_e);
-  const HistoryActionID HistoryActionID::INSTALL(HistoryActionID::INSTALL_e);
-  const HistoryActionID HistoryActionID::REMOVE(HistoryActionID::REMOVE_e);
-  const HistoryActionID HistoryActionID::REPO_ADD(HistoryActionID::REPO_ADD_e);
-  const HistoryActionID HistoryActionID::REPO_REMOVE(HistoryActionID::REPO_REMOVE_e);
-  const HistoryActionID HistoryActionID::REPO_CHANGE_ALIAS(HistoryActionID::REPO_CHANGE_ALIAS_e);
-  const HistoryActionID HistoryActionID::REPO_CHANGE_URL(HistoryActionID::REPO_CHANGE_URL_e);
+    static std::string pidAndAppname()
+    {
+      static std::string _val;
+      if ( _val.empty() )
+      {
+       pid_t mypid = getpid();
+       zypp::Pathname p( "/proc/"+zypp::str::numstring(mypid)+"/exe" );
+       zypp::Pathname myname( zypp::filesystem::readlink( p ) );
 
-  HistoryActionID::HistoryActionID(const std::string & strval_r)
-    : _id(parse(strval_r))
-  {}
+       _val += zypp::str::numstring(mypid);
+       _val += ":";
+       _val += myname.basename();
+      }
+      return _val;
+    }
 
-  HistoryActionID::ID HistoryActionID::parse(const std::string & strval_r)
-  {
-    if (_table.empty())
+    static std::string cmdline()
     {
-      // initialize it
-      _table["install"] = INSTALL_e;
-      _table["remove"]  = REMOVE_e;
-      _table["radd"]    = REPO_ADD_e;
-      _table["rremove"] = REPO_REMOVE_e;
-      _table["ralias"]  = REPO_CHANGE_ALIAS_e;
-      _table["rurl"]    = REPO_CHANGE_URL_e;
-      _table["NONE"] = _table["none"] = HistoryActionID::NONE_e;
+      static std::string _val;
+      if ( _val.empty() )
+      {
+       pid_t mypid = getpid();
+       {
+         std::ifstream cmdlineStr( Pathname("/proc/"+zypp::str::numstring(mypid)+"/cmdline").c_str() );
+         char ch;
+         const char * sep = "'";
+         while ( cmdlineStr && cmdlineStr.get( ch ) )
+         {
+           if ( sep )
+           {
+             _val += sep;
+             sep = nullptr;
+           }
+           switch ( ch )
+           {
+             case '\0':        _val += '\''; sep = " '"; break;
+             case '\n':        _val += ' '; break;
+             case '\\':        _val += '\\'; _val += '\\'; break;
+             case '|':         _val += '\\'; _val += '|'; break;
+             default:          _val += ch; break;
+           }
+         }
+       }
+      }
+      return _val;
     }
+  } // namespace
 
-    std::map<std::string,HistoryActionID::ID>::const_iterator it =
-      _table.find(strval_r);
-
-    if (it == _table.end())
-      WAR << "Unknown history action ID '" + strval_r + "'";
+  namespace
+  {
+    const char         _sep = '|';
+    std::ofstream      _log;
+    unsigned           _refcnt = 0;
+    Pathname           _fname;
+    Pathname           _fnameLastFail;
 
-    return it->second;
-  }
+    inline void openLog()
+    {
+      if ( _fname.empty() )
+        _fname = ZConfig::instance().historyLogFile();
 
+      _log.clear();
+      _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app );
+      if( !_log && _fnameLastFail != _fname )
+      {
+        ERR << "Could not open logfile '" << _fname << "'" << endl;
+       _fnameLastFail = _fname;
+      }
+    }
 
-  const std::string & HistoryActionID::asString(bool pad) const
-  {
-    static std::map<ID, std::string> _table;
-    if ( _table.empty() )
+    inline void closeLog()
     {
-      // initialize it
-      _table[INSTALL_e]           = "install";
-      _table[REMOVE_e]            = "remove";
-      _table[REPO_ADD_e]          = "radd";
-      _table[REPO_REMOVE_e]       = "rremove";
-      _table[REPO_CHANGE_ALIAS_e] = "ralias";
-      _table[REPO_CHANGE_URL_e]   = "rurl";
-      _table[NONE_e]              = "NONE";
+      _log.clear();
+      _log.close();
     }
-    // add spaces so that the size of the returned string is always 7 (for now)
-    if (pad)
-      return _table[_id].append(7 - _table[_id].size(), ' ');
-    return _table[_id];
-  }
 
-  std::ostream & operator << (std::ostream & str, const HistoryActionID & id)
-  { return str << id.asString(); }
+    inline void refUp()
+    {
+      if ( !_refcnt )
+        openLog();
+      ++_refcnt;
+    }
 
-  ///////////////////////////////////////////////////////////////////
+    inline void refDown()
+    {
+      --_refcnt;
+      if ( !_refcnt )
+        closeLog();
+    }
+  } // namespace
 
   ///////////////////////////////////////////////////////////////////
   //
@@ -126,61 +149,26 @@ namespace zypp
   //
   ///////////////////////////////////////////////////////////////////
 
-  Pathname HistoryLog::_fname(ZConfig::instance().historyLogFile());
-  std::ofstream HistoryLog::_log;
-  unsigned HistoryLog::_refcnt = 0;
-  const char HistoryLog::_sep = '|';
-
-  ///////////////////////////////////////////////////////////////////
-
   HistoryLog::HistoryLog( const Pathname & rootdir )
   {
+    setRoot( rootdir );
     refUp();
-    if (!rootdir.empty() && rootdir.absolute())
-      _fname = rootdir / ZConfig::instance().historyLogFile();
   }
 
-  void HistoryLog::openLog()
+  HistoryLog::~HistoryLog()
   {
-    if ( !_fname.empty() )
-    {
-      _log.clear();
-      _log.open( _fname.asString().c_str(), std::ios::out|std::ios::app );
-      if( !_log )
-        ERR << "Could not open logfile '" << _fname << "'" << endl;
-    }
+    refDown();
   }
 
-  void HistoryLog::closeLog()
-  {
-    _log.clear();
-    _log.close();
-  }
-
-  void HistoryLog::refUp()
-  {
-    if ( !_refcnt )
-      openLog();
-    ++_refcnt;
-  }
-
-  void HistoryLog::refDown()
-  {
-    --_refcnt;
-    if ( !_refcnt )
-      closeLog();
-  }
-
-
   void HistoryLog::setRoot( const Pathname & rootdir )
   {
-    if (rootdir.empty() || !rootdir.absolute())
+    if ( ! rootdir.absolute() )
       return;
 
     if ( _refcnt )
       closeLog();
 
-    _fname = rootdir / "/var/log/zypp/history";
+    _fname = rootdir / ZConfig::instance().historyLogFile();
     filesystem::assert_dir( _fname.dirname() );
     MIL << "installation log file " << _fname << endl;
 
@@ -188,20 +176,23 @@ namespace zypp
       openLog();
   }
 
-
   const Pathname & HistoryLog::fname()
-  { return _fname; }
+  {
+    if ( _fname.empty() )
+      _fname = ZConfig::instance().historyLogFile();
+    return _fname;
+  }
 
   /////////////////////////////////////////////////////////////////////////
 
-  void HistoryLog::comment( const string & comment, bool timestamp )
+  void HistoryLog::comment( const string & comment, bool timestamp_r )
   {
     if (comment.empty())
       return;
 
     _log << "# ";
-    if ( timestamp )
-      _log << ::timestamp() << " ";
+    if ( timestamp_r )
+      _log << timestamp() << " ";
 
     const char * s = comment.c_str();
     const char * c = s;
@@ -225,63 +216,70 @@ namespace zypp
   }
 
   /////////////////////////////////////////////////////////////////////////
-  
+
+  void HistoryLog::stampCommand()
+  {
+    _log
+      << timestamp()                                                   // 1 timestamp
+      << _sep << HistoryActionID::STAMP_COMMAND.asString(true)         // 2 action
+      << _sep << userAtHostname()                                      // 3 requested by
+      << _sep << cmdline()                                             // 4 command
+      << _sep << str::escape(ZConfig::instance().userData(), _sep)     // 6 userdata
+      << endl;
+
+  }
+
   void HistoryLog::install( const PoolItem & pi )
   {
+    if ( ! pi.isKind<Package>() ) return;
     const Package::constPtr p = asKind<Package>(pi.resolvable());
-    if (!p)
-      return;
 
     _log
-      << timestamp()                                   // 1 timestamp
-      << _sep << HistoryActionID::INSTALL.asString(true) // 2 action
-      << _sep << p->name()                             // 3 name
-      << _sep << p->edition()                          // 4 evr
-      << _sep << p->arch();                            // 5 arch
-
-    if (pi.status().isByUser())
-      _log << _sep << userAtHostname();                // 6 reqested by
-    //else if (pi.status().isByApplHigh() || pi.status().isByApplLow())
-    //  _log << _sep << "appl";
+      << timestamp()                                                   // 1 timestamp
+      << _sep << HistoryActionID::INSTALL.asString(true)               // 2 action
+      << _sep << p->name()                                             // 3 name
+      << _sep << p->edition()                                          // 4 evr
+      << _sep << p->arch();                                            // 5 arch
+
+    // ApplLow is what the solver selected on behalf of the user.
+    if (pi.status().isByUser() || pi.status().isByApplLow() )
+      _log << _sep << userAtHostname();                                        // 6 requested by
+    else if (pi.status().isByApplHigh())
+      _log << _sep << pidAndAppname();
     else
       _log << _sep;
 
     _log
-      << _sep << p->repoInfo().alias()                 // 7 repo alias
-      << _sep << p->checksum().checksum();             // 8 checksum
-
-    _log << endl; 
-
-    //_log << pi << endl;
+      << _sep << p->repoInfo().alias()                                 // 7 repo alias
+      << _sep << p->checksum().checksum()                              // 8 checksum
+      << _sep << str::escape(ZConfig::instance().userData(), _sep)     // 9 userdata
+      << endl;
   }
 
 
   void HistoryLog::remove( const PoolItem & pi )
   {
+    if ( ! pi.isKind<Package>() ) return;
     const Package::constPtr p = asKind<Package>(pi.resolvable());
-    if (!p)
-      return;
 
     _log
-      << timestamp()                                   // 1 timestamp
-      << _sep << HistoryActionID::REMOVE.asString(true) // 2 action
-      << _sep << p->name()                             // 3 name
-      << _sep << p->edition()                          // 4 evr
-      << _sep << p->arch();                            // 5 arch
-
-    if (pi.status().isByUser())
-      _log << _sep << userAtHostname();                // 6 reqested by
-    //else if (pi.status().isByApplHigh() || pi.status().isByApplLow())
-    //  _log << _sep << "appl";
+      << timestamp()                                                   // 1 timestamp
+      << _sep << HistoryActionID::REMOVE.asString(true)                        // 2 action
+      << _sep << p->name()                                             // 3 name
+      << _sep << p->edition()                                          // 4 evr
+      << _sep << p->arch();                                            // 5 arch
+
+    // ApplLow is what the solver selected on behalf of the user.
+    if ( pi.status().isByUser() || pi.status().isByApplLow() )
+      _log << _sep << userAtHostname();                                        // 6 requested by
+    else if (pi.status().isByApplHigh())
+      _log << _sep << pidAndAppname();
     else
       _log << _sep;
 
-    // we don't have checksum in rpm db
-    //  << _sep << p->checksum().checksum();           // x checksum
-
-    _log << endl; 
-
-    //_log << pi << endl;
+    _log
+      << _sep << str::escape(ZConfig::instance().userData(), _sep)     // 7 userdata
+      << endl;
   }
 
   /////////////////////////////////////////////////////////////////////////
@@ -289,11 +287,11 @@ namespace zypp
   void HistoryLog::addRepository(const RepoInfo & repo)
   {
     _log
-      << timestamp()                                   // 1 timestamp
-      << _sep << HistoryActionID::REPO_ADD.asString(true) // 2 action 
-      << _sep << repo.alias()                          // 3 alias
-      // what about the rest of the URLs??
-      << _sep << *repo.baseUrlsBegin()                 // 4 primary URL
+      << timestamp()                                                   // 1 timestamp
+      << _sep << HistoryActionID::REPO_ADD.asString(true)              // 2 action
+      << _sep << str::escape(repo.alias(), _sep)                       // 3 alias
+      << _sep << str::escape(repo.url().asString(), _sep)              // 4 primary URL
+      << _sep << str::escape(ZConfig::instance().userData(), _sep)     // 5 userdata
       << endl;
   }
 
@@ -301,9 +299,10 @@ namespace zypp
   void HistoryLog::removeRepository(const RepoInfo & repo)
   {
     _log
-      << timestamp()                                   // 1 timestamp
-      << _sep << HistoryActionID::REPO_REMOVE.asString(true) // 2 action 
-      << _sep << str::escape(repo.alias(), _sep)       // 3 alias
+      << timestamp()                                                   // 1 timestamp
+      << _sep << HistoryActionID::REPO_REMOVE.asString(true)           // 2 action
+      << _sep << str::escape(repo.alias(), _sep)                       // 3 alias
+      << _sep << str::escape(ZConfig::instance().userData(), _sep)     // 4 userdata
       << endl;
   }
 
@@ -314,22 +313,45 @@ namespace zypp
     if (oldrepo.alias() != newrepo.alias())
     {
       _log
-        << timestamp()                                    // 1 timestamp
-        << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true) // 2 action
-        << _sep << str::escape(oldrepo.alias(), _sep)     // 3 old alias
-        << _sep << str::escape(newrepo.alias(), _sep);    // 4 new alias
+        << timestamp()                                                 // 1 timestamp
+        << _sep << HistoryActionID::REPO_CHANGE_ALIAS.asString(true)   // 2 action
+        << _sep << str::escape(oldrepo.alias(), _sep)                  // 3 old alias
+        << _sep << str::escape(newrepo.alias(), _sep)                  // 4 new alias
+        << _sep << str::escape(ZConfig::instance().userData(), _sep)   // 5 userdata
+        << endl;
     }
-    
-    if (*oldrepo.baseUrlsBegin() != *newrepo.baseUrlsBegin())
+    if ( oldrepo.url() != newrepo.url() )
     {
       _log
-        << timestamp()                                    // 1 timestamp
-        << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true) // 2 action
-        << _sep << str::escape(oldrepo.alias(), _sep)              // 3 old url
-        << _sep << *newrepo.baseUrlsBegin();                       // 4 new url
+        << timestamp()                                                 // 1 timestamp
+        << _sep << HistoryActionID::REPO_CHANGE_URL.asString(true)     // 2 action
+        << _sep << str::escape(oldrepo.url().asString(), _sep)         // 3 old url
+        << _sep << str::escape(newrepo.url().asString(), _sep)         // 4 new url
+        << _sep << str::escape(ZConfig::instance().userData(), _sep)   // 5 userdata
+        << endl;
     }
   }
 
+  void HistoryLog::patchStateChange( const PoolItem & pi, ResStatus::ValidateValue oldstate )
+  {
+    if ( ! pi.isKind<Patch>() ) return;
+    const Patch::constPtr p = asKind<Patch>(pi.resolvable());
+
+    _log
+      << timestamp()                                                   // 1 timestamp
+      << _sep << HistoryActionID::PATCH_STATE_CHANGE.asString(true)    // 2 action
+      << _sep << p->name()                                             // 3 name
+      << _sep << p->edition()                                          // 4 evr
+      << _sep << p->arch()                                             // 5 arch
+      << _sep << p->repoInfo().alias()                                 // 6 repo alias
+      << _sep << p->severity()                                         // 7 severity
+      << _sep << p->category()                                         // 8 category
+      << _sep << ResStatus::validateValueAsString( oldstate )          // 9 old state
+      << _sep << pi.status().validateValueAsString()                   // 10 new state
+      << _sep << str::escape(ZConfig::instance().userData(), _sep)     // 11 userdata
+      << endl;
+  }
+
   ///////////////////////////////////////////////////////////////////
 
 } // namespace zypp