namespace
{
inline string timestamp()
- { return zypp::Date::now().form( "%Y-%m-%d %H:%M:%S" ); }
+ { return zypp::Date::now().form( HISTORY_LOG_DATE_FORMAT ); }
inline string userAtHostname()
{
action = HistoryActionID(str::trim(fields[1]));
}
+ void HistoryItem::dumpTo(ostream & str) const
+ {
+ str << date.form(HISTORY_LOG_DATE_FORMAT) << "|" << action.asString();
+ }
+
+ ostream & operator<<(ostream & str, const HistoryItem & obj)
+ {
+ obj.dumpTo(str);
+ return str;
+ }
+
+
/////////////////////////////////////////////////////////////////////
//
// CLASS NAME: HistoryItemInstall
checksum = CheckSum::sha(fields[7]);
}
- const std::string HistoryItemInstall::asString() const
+ void HistoryItemInstall::dumpTo(ostream & str) const
{
- ostringstream str;
- str
- << date.form(HISTORY_LOG_DATE_FORMAT) << "|"
- << action.asString() << "|"
+ HistoryItem::dumpTo(str);
+ str << "|"
<< name << "|"
<< edition << "|"
<< arch << "|"
<< reqby << "|"
<< repoalias << "|"
<< checksum;
- return str.str();
}
- std::ostream & operator<<(std::ostream & str, const HistoryItemInstall & obj)
+ ostream & operator<<(ostream & str, const HistoryItemInstall & obj)
{
- return str << obj.asString();
+ obj.dumpTo(str);
+ return str;
}
reqby = fields[5];
}
+ void HistoryItemRemove::dumpTo(ostream & str) const
+ {
+ HistoryItem::dumpTo(str);
+ str << "|"
+ << name << "|"
+ << edition << "|"
+ << arch << "|"
+ << reqby;
+ }
+
+ ostream & operator<<(ostream & str, const HistoryItemRemove & obj)
+ {
+ obj.dumpTo(str);
+ return str;
+ }
+
/////////////////////////////////////////////////////////////////////
//
url = Url(fields[3]);
}
+ void HistoryItemRepoAdd::dumpTo(ostream & str) const
+ {
+ HistoryItem::dumpTo(str);
+ str << "|"
+ << alias << "|"
+ << url;
+ }
+
+ ostream & operator<<(ostream & str, const HistoryItemRepoAdd & obj)
+ {
+ obj.dumpTo(str);
+ return str;
+ }
+
/////////////////////////////////////////////////////////////////////
//
alias = fields[2];
}
+ void HistoryItemRepoRemove::dumpTo(ostream & str) const
+ {
+ HistoryItem::dumpTo(str);
+ str << "|" << alias;
+ }
+
+ ostream & operator<<(ostream & str, const HistoryItemRepoRemove & obj)
+ {
+ obj.dumpTo(str);
+ return str;
+ }
+
/////////////////////////////////////////////////////////////////////
//
newalias = fields[3];
}
+ void HistoryItemRepoAliasChange::dumpTo(ostream & str) const
+ {
+ HistoryItem::dumpTo(str);
+ str << "|" << oldalias << "|" << newalias;
+ }
+
+ ostream & operator<<(ostream & str, const HistoryItemRepoAliasChange & obj)
+ {
+ obj.dumpTo(str);
+ return str;
+ }
+
/////////////////////////////////////////////////////////////////////
//
newurl = Url(fields[3]);
}
+ void HistoryItemRepoUrlChange::dumpTo(ostream & str) const
+ {
+ HistoryItem::dumpTo(str);
+ str << "|" << alias << "|" << newurl;
+ }
+
+ ostream & operator<<(ostream & str, const HistoryItemRepoUrlChange & obj)
+ {
+ obj.dumpTo(str);
+ return str;
+ }
+
}
#ifndef ZYPP_HISTORYLOGDATA_H_
#define ZYPP_HISTORYLOGDATA_H_
+#include <iosfwd>
+
#include "zypp/Date.h"
#include "zypp/Edition.h"
#include "zypp/Arch.h"
virtual ~HistoryItem()
{}
+ virtual void dumpTo(std::ostream & str) const;
+
public:
Date date;
HistoryActionID action;
virtual ~HistoryItemInstall()
{}
- virtual const std::string asString() const;
+ virtual void dumpTo(std::ostream & str) const;
public:
std::string name;
virtual ~HistoryItemRemove()
{}
+ virtual void dumpTo(std::ostream & str) const;
+
public:
std::string name;
Edition edition;
virtual ~HistoryItemRepoAdd()
{}
+ virtual void dumpTo(std::ostream & str) const;
+
public:
std::string alias;
Url url;
virtual ~HistoryItemRepoRemove()
{}
+ virtual void dumpTo(std::ostream & str) const;
+
public:
std::string alias;
};
virtual ~HistoryItemRepoAliasChange()
{}
+ virtual void dumpTo(std::ostream & str) const;
+
public:
std::string oldalias;
std::string newalias;
virtual ~HistoryItemRepoUrlChange()
{}
+ virtual void dumpTo(std::ostream & str) const;
+
public:
std::string alias;
Url newurl;
};
/////////////////////////////////////////////////////////////////////
+ std::ostream & operator<<(std::ostream & str, const HistoryItem & obj);
}
/////////////////////////////////////////////////////////////////////
//
- // CLASS NAME: HistoryLogReader
+ // CLASS NAME: HistoryLogReader::Impl
//
/////////////////////////////////////////////////////////////////////
- HistoryLogReader::HistoryLogReader( const Pathname & historyFile,
- const ProcessItem & callback )
- : _filename(historyFile), _callback(callback)
+ struct HistoryLogReader::Impl
+ {
+ Impl( const Pathname & historyFile, const ProcessItem & callback );
+ ~Impl()
+ {}
+
+ HistoryItem::Ptr createHistoryItem(HistoryItem::FieldVector & fields);
+
+ void readAll(const ProgressData::ReceiverFnc & progress);
+
+ Pathname _filename;
+ ProcessItem _callback;
+ bool _ignoreInvalid;
+ };
+
+ HistoryLogReader::Impl::Impl( const Pathname & historyFile,
+ const ProcessItem & callback )
+ : _filename(historyFile), _callback(callback), _ignoreInvalid(false)
{}
- void HistoryLogReader::readAll(const ProgressData::ReceiverFnc & progress)
+ HistoryItem::Ptr
+ HistoryLogReader::Impl::createHistoryItem(HistoryItem::FieldVector & fields)
+ {
+ HistoryActionID aid(str::trim(fields[1]));
+ switch (aid.toEnum())
+ {
+ case HistoryActionID::INSTALL_e:
+ return HistoryItemInstall::Ptr(new HistoryItemInstall(fields));
+ break;
+
+ case HistoryActionID::REMOVE_e:
+ return HistoryItemRemove::Ptr(new HistoryItemRemove(fields));
+ break;
+
+ case HistoryActionID::REPO_ADD_e:
+ return HistoryItemRepoAdd::Ptr(new HistoryItemRepoAdd(fields));
+ break;
+
+ case HistoryActionID::REPO_REMOVE_e:
+ return HistoryItemRepoRemove::Ptr(new HistoryItemRepoRemove(fields));
+ break;
+
+ case HistoryActionID::REPO_CHANGE_ALIAS_e:
+ return HistoryItemRepoAliasChange::Ptr(new HistoryItemRepoAliasChange(fields));
+ break;
+
+ case HistoryActionID::REPO_CHANGE_URL_e:
+ return HistoryItemRepoUrlChange::Ptr(new HistoryItemRepoUrlChange(fields));
+ break;
+
+ default:
+ WAR << "Unknown history log action type: " << fields[1] << endl;
+ }
+
+ return HistoryItem::Ptr();
+ }
+
+ void HistoryLogReader::Impl::readAll(const ProgressData::ReceiverFnc & progress)
{
InputStream is(_filename);
iostr::EachLine line(is);
pd.sendTo( progress );
pd.toMin();
- for (; line; line.next(), pd.tick())
+ HistoryItem::FieldVector fields;
+ HistoryItem::Ptr item_ptr;
+ for (; line; line.next(), pd.tick(), fields.clear(), item_ptr.reset())
{
const string & s = *line;
if (s[0] == '#') // ignore comments
continue;
- // determine action
- HistoryItem::FieldVector fields;
+ // parse fields
str::splitEscaped(s, back_inserter(fields), "|", true);
if (fields.size() <= 2)
str::form("Bad number of fields. Got %ld, expected more than %d.",
fields.size(), 2)));
- // parse into the data structures
- HistoryActionID aid(str::trim(fields[1]));
try
{
- switch (aid.toEnum())
- {
- case HistoryActionID::INSTALL_e:
- _callback(HistoryItemInstall::Ptr(new HistoryItemInstall(fields)));
- break;
-
- case HistoryActionID::REMOVE_e:
- _callback(HistoryItemRemove::Ptr(new HistoryItemRemove(fields)));
- break;
-
- case HistoryActionID::REPO_ADD_e:
- _callback(HistoryItemRepoAdd::Ptr(new HistoryItemRepoAdd(fields)));
- break;
-
- case HistoryActionID::REPO_REMOVE_e:
- _callback(HistoryItemRepoRemove::Ptr(new HistoryItemRepoRemove(fields)));
- break;
-
- case HistoryActionID::REPO_CHANGE_ALIAS_e:
- _callback(HistoryItemRepoAliasChange::Ptr(new HistoryItemRepoAliasChange(fields)));
- break;
-
- case HistoryActionID::REPO_CHANGE_URL_e:
- _callback(HistoryItemRepoUrlChange::Ptr(new HistoryItemRepoUrlChange(fields)));
- break;
+ item_ptr = createHistoryItem(fields);
+ }
+ catch (const Exception & e)
+ {
+ ZYPP_CAUGHT(e);
+ ERR << "Invalid history log entry on line #" << line.lineNo() << ":" << endl
+ << s << endl;
- default:
- WAR << "Unknown history log action type: " << fields[1] << endl;
+ if (!_ignoreInvalid)
+ {
+ ParseException newe(
+ str::form("Error in history log on line #%u.", line.lineNo() ) );
+ newe.remember(e);
+ ZYPP_THROW(newe);
}
}
- catch (const Exception & e)
+
+ if (item_ptr)
+ _callback(item_ptr);
+ else if (!_ignoreInvalid)
{
- ParseException newe(
- str::form("Error in history log on line #%u.", line.lineNo()));
- newe.remember(e);
- ZYPP_THROW(newe);
+ ParseException
+ e(str::form("Error in history log on line #%u.", line.lineNo()));
+ e.addHistory("Unknown entry type.");
+ ZYPP_THROW(e);
}
}
}
+ /////////////////////////////////////////////////////////////////////
+ //
+ // CLASS NAME: HistoryLogReader
+ //
+ /////////////////////////////////////////////////////////////////////
+
+ HistoryLogReader::HistoryLogReader( const Pathname & historyFile,
+ const ProcessItem & callback )
+ : _pimpl(new HistoryLogReader::Impl(historyFile, callback))
+ {}
+
HistoryLogReader::~HistoryLogReader()
{}
+ void HistoryLogReader::setIgnoreInvalidItems(bool ignoreInvalid)
+ { _pimpl->_ignoreInvalid = ignoreInvalid; }
+
+ bool HistoryLogReader::ignoreInvalidItems() const
+ { return _pimpl->_ignoreInvalid; }
+
+ void HistoryLogReader::readAll(const ProgressData::ReceiverFnc & progress)
+ { _pimpl->readAll(progress); }
+
/////////////////////////////////////////////////////////////////
} // namespace parser
// CLASS NAME: HistoryLogReader
//
/**
+ * Reads a zypp history log file and calls the ProcessItem function passed
+ * in the constructor for each item found.
*
+ * Example:
+ * <code>
+ *
+ * struct HistoryItemCollector
+ * {
+ * vector<HistoryItem::Ptr> items;
+ *
+ * bool processEntry( const HistoryItem::Ptr & item_ptr )
+ * {
+ * items.push_back(item_ptr);
+ * return true;
+ * }
+ * }
+ *
+ * ...
+ *
+ * HistoryItemCollector ic;
+ * HistoryLogReader reader("/var/log/zypp/history", boost::ref(ic));
+ *
+ * try
+ * {
+ * reader.readAll();
+ * }
+ * catch (const Exception & e)
+ * {
+ * cout << e.asUserHistory() << endl;
+ * }
+ *
+ * </code>
+ *
+ * \see http://en.opensuse.org/Libzypp/Package_History
*/
class HistoryLogReader
{
* Read the whole log file.
*/
void readAll(
- const ProgressData::ReceiverFnc &progress = ProgressData::ReceiverFnc());
+ const ProgressData::ReceiverFnc &progress = ProgressData::ReceiverFnc() );
+
+ /**
+ * Read log from specified \a date.
+ */
+ void readFrom( const Date & date,
+ const ProgressData::ReceiverFnc &progress = ProgressData::ReceiverFnc() );
- /*
- * readFrom(Date);
- * readFromTo(Date, Date);
+ /**
+ * Read log between \a fromDate and \a toDate.
+ */
+ void readFromTo( const Date & fromDate, const Date & toDate,
+ const ProgressData::ReceiverFnc &progress = ProgressData::ReceiverFnc() );
+
+ /**
+ * Set the reader to ignore invalid log entries and continue with the rest.
+ *
+ * \param ignoreInvalid <tt>true</tt> will cause the reader to ignore invalid entries
*/
+ void setIgnoreInvalidItems( bool ignoreInvalid = false );
+
+ /**
+ * Whether the reader is set to ignore invalid log entries.
+ */
+ bool ignoreInvalidItems() const;
private:
- Pathname _filename;
- ProcessItem _callback;
+ /** Implementation */
+ class Impl;
+ RW_pointer<Impl,rw_pointer::Scoped<Impl> > _pimpl;
};
+ ///////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////