/* * portmgr.cc * * Copyright (c) 2002, 2003 Frerich Raabe * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. For licensing and distribution details, check the * accompanying file 'COPYING'. */ #include "databasewrapper.h" #include "port.h" #include "portmgr.h" #include "process.h" #include #include #include #include #include #include #include #include #include // for getenv() // This would be nice in Qt template Container qUnique( const Container &container ) { Container c; typename Container::ConstIterator it = container.begin(); typename Container::ConstIterator end = container.end(); for ( ; it != end; ++it ) if ( c.find( *it ) == c.end() ) c << *it; return c; } using namespace Barry; PortMgr *PortMgr::m_instance = 0; PortMgr &PortMgr::self() { if ( !m_instance ) m_instance = new PortMgr; return *m_instance; } PortMgr::PortMgr() : m_portDb( 0 ), m_pkgDb( 0 ) { reparseConfig(); } PortMgr::~PortMgr() { delete m_portDb; delete m_pkgDb; } void PortMgr::reparseConfig() { KConfig *cfg = kapp->config(); cfg->setGroup( "General" ); #ifdef __NetBSD__ m_portRootDir = QString::fromLatin1( "/usr/opt" ); #else m_portRootDir = QString::fromLatin1( "/usr/ports" ); #endif QString portDirDefault = QString::fromLatin1( ::getenv( "PORTSDIR" ) ); if ( portDirDefault.isEmpty() ) portDirDefault = getMkVariable( QString::fromLatin1( "PORTSDIR" ) ); if ( portDirDefault.isEmpty() ) portDirDefault = m_portRootDir; m_portRootDir = cfg->readEntry( QString::fromLatin1( "Port directory" ), portDirDefault ).stripWhiteSpace(); QString pkgRootDirDefault = QString::fromLatin1( ::getenv( "PKG_DBDIR" ) ); if ( pkgRootDirDefault.isEmpty() ) pkgRootDirDefault = getMkVariable( QString::fromLatin1( "PKG_DBDIR" ) ); if ( pkgRootDirDefault.isEmpty() ) pkgRootDirDefault = QString::fromLatin1( "/var/db/pkg" ); m_pkgRootDir = cfg->readEntry( QString::fromLatin1( "Package directory" ), pkgRootDirDefault).stripWhiteSpace(); } bool PortMgr::load() { checkDatabase(); return loadPortDb() && loadPkgDb(); } bool PortMgr::loadPortDb() { QString portDbFile = m_portRootDir + QString::fromLatin1( "/INDEX.db" ); if ( !QFile::exists( portDbFile ) ) { KNotifyClient::event( KNotifyClient::fatalError, i18n( "The directory %1 seems to be invalid, " "failed to locate the port database.
" "
" "Please make sure that you installed the 'ports' " "distribution and that the directory %1 was mounted " "properly, if necessary.
" "
" "Also, make sure that the file %1/INDEX.db exists; if " "it doesn't, run portsdb -u as root to generate " "it.
") .arg( m_portRootDir ).arg( m_portRootDir ).arg( m_portRootDir ) ); return false; } delete m_portDb; m_portDb = new DatabaseWrapper( portDbFile ); if ( !m_portDb->open() ) { KNotifyClient::event( KNotifyClient::fatalError, i18n( "Failed to load the port database %1!
" "
" "Did you specify an invalid port directory by any " "chance?The directory %1 seems to be invalid, " "failed to locate the package database.
" "
" "Please make sure that the directory %1 was mounted " "properly, if necessary.
" "
" "Also, make sure that the file %1/pkgdb.db exists; if " "it doesn't, run pkgdb -u as root to generate " "it.") .arg( m_pkgRootDir ).arg( m_pkgRootDir ).arg( m_pkgRootDir ) ); return false; } delete m_pkgDb; m_pkgDb = new DatabaseWrapper( pkgDbFile ); if ( !m_pkgDb->open() ) { KNotifyClient::event( KNotifyClient::fatalError, i18n( "Failed to load the package database %1!
" "
" "Did you specify an invalid package directory by any " "chance?getEntry( QString::fromLatin1( ":categories" ) ); cat += QString::fromLatin1( " " ); cat += m_portDb->getEntry( QString::fromLatin1( ":virtual_categories" ) ); return QStringList::split( ' ', cat ); } PortList PortMgr::ports( const QString &category ) const { if ( !m_portDb ) return PortList(); PortList ports; const QString origins = m_portDb->getEntry( QString::fromLatin1( "?" ) + category ); const QStringList tokens = QStringList::split( ' ', origins ); QStringList::ConstIterator it = tokens.begin(); QStringList::ConstIterator end = tokens.end(); for ( ; it != end; ++it ) ports += Port( *it ); // Sort out duplicate entries; there is a bug in the way the INDEX file // gets built :-( return qUnique( ports ); } PortList PortMgr::allPorts() const { if ( m_allPorts.isEmpty() ) determineAllPorts(); return m_allPorts; } void PortMgr::determineAllPorts() const { if ( !m_portDb ) return; const QString origins = m_portDb->getEntry( QString::fromLatin1( ":origins" ) ); const QStringList tokens = QStringList::split( ' ', origins ); QStringList::ConstIterator it = tokens.begin(); QStringList::ConstIterator end = tokens.end(); for ( ; it != end; ++it ) m_allPorts += Port( *it ); } PortList PortMgr::installedPorts() const { if ( m_installedPorts.isEmpty() ) determineInstalledPorts(); return m_installedPorts; } void PortMgr::determineInstalledPorts() const { if ( !m_pkgDb ) return; const QString origins = m_pkgDb->getEntry( QString::fromLatin1( ":origins" ) ); const QStringList entries = QStringList::split( ' ', origins ); QStringList::ConstIterator it = entries.begin(); QStringList::ConstIterator end = entries.end(); for ( ; it != end; ++it ) { const QString pkgName = m_pkgDb->getEntry( QString::fromLatin1( "?" ) + *it ); m_installedPorts += Port::fromPkgName( *it, pkgName ); } } QDateTime PortMgr::portDatabaseTimestamp() const { const QFileInfo fi( m_portRootDir + QString::fromLatin1( "/INDEX.db" ) ); return fi.lastModified(); } QDateTime PortMgr::packageDatabaseTimestamp() const { const QFileInfo fi( m_pkgRootDir + QString::fromLatin1( "/pkgdb.db" ) ); return fi.lastModified(); } QString PortMgr::getMkVariable( const QString &key ) const { const QString cmd = QString::fromLatin1( "make -f%1/Mk/bsd.port.mk -V%2" ) .arg( m_portRootDir ).arg( key ); return Process::execute( cmd, Process::Stdout ); } QStringList PortMgr::getMkVariables( const QStringList &keys ) const { QString cmd = QString::fromLatin1( "make -f%1/Mk/bsd.port.mk" ) .arg( m_portRootDir ); QStringList::ConstIterator it = keys.begin(); QStringList::ConstIterator end = keys.end(); for ( ; it != end; ++it ) cmd += QString::fromLatin1( " -V%1" ).arg( *it ); const QString output = Process::execute( cmd, Process::Stdout ); return QStringList::split( '\n', output ); } void PortMgr::checkDatabase() const { KConfig *cfg = kapp->config(); cfg->setGroup( QString::fromLatin1( "General" ) ); const QString supfileName = cfg->readEntry( QString::fromLatin1( "CVSup supfile" ) ); QFile supfile( supfileName ); if ( !supfile.open( IO_ReadOnly ) ) { kdWarning() << "Couldn't open supfile " << supfileName << endl; return; } const QRegExp rx = QString::fromLatin1( "^\\*default\\s+base=" ); QString line; QTextStream stream( &supfile ); while ( !stream.atEnd() && line.find( rx ) == -1 ) line = stream.readLine(); if ( line.find( rx ) == -1 ) line = QString::fromLatin1( "*default base=/usr/local/etc/cvsup" ); line = line.mid( line.find( '=' ) + 1 ).stripWhiteSpace(); const QString checkoutsFileName = line + QString::fromLatin1( "/sup/ports-all/checkouts.cvs:." ); if ( !QFile::exists( checkoutsFileName ) ) { kdWarning() << "Could not check checkouts file " << checkoutsFileName << endl; return; } const bool portDbOutdated = PortMgr::self().portDatabaseTimestamp() < QFileInfo( checkoutsFileName ).lastModified(); if ( portDbOutdated ) { const QString errorMsg = i18n( "Your port database is not up to date, this means that " "Barry cannot function properly. It is strongly advised " "that you quit Barry and update your port database." ); const QString detailedErrorMsg = i18n( "Barry uses the database file %1 for a lot of features " "it provides and detected that this file is not up to date, " "which means that you updated your ports tree in %2 " "without running portsdb -u afterwards.
" "
" "You can resolve this by exiting Barry and running (as " "root) the command portsdb -u now. After that, " "re-start Barry.
" "
" "If you do not update your database, the data shown by " "Barry (such as the list of available ports, the version " "numbers, and much more) does not reflect the actual " "situation on your system!" ) .arg( m_portRootDir + QString::fromLatin1( "/INDEX.db" ) ) .arg( m_portRootDir ); KMessageBox::detailedError( 0, errorMsg, detailedErrorMsg, i18n( "Database outdated" ) ); } } #include "portmgr.moc" // vim:ts=4:sw=4:noet:list