/* * port.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 "filelistretriever.h" #include "port.h" #include "portmgr.h" #include #include #include #include #include // for getenv() namespace Barry { class ConcretePort : public PortInterface { public: ConcretePort( const QString &origin ); virtual QString origin() const; virtual QString name() const; virtual QString version() const; virtual QString installedVersion() const; virtual QString directory() const; virtual QString prefix() const; virtual QString comment() const; virtual QString description() const; virtual QString maintainer() const; virtual QStringList categories() const; virtual PortList buildDeps() const; virtual PortList runDeps() const; virtual QString link() const; virtual QStringList files() const; virtual QStringList installedFiles() const; virtual bool installed() const; virtual long long size() const; private: void determineSize(); PortList parseDeps( const QString &depString ) const; QString m_origin; QString m_name; QString m_version; QString m_directory; QString m_prefix; QString m_comment; QString m_description; QString m_maintainer; QStringList m_categories; PortList m_buildDeps; PortList m_runDeps; QString m_link; long long m_size; }; } // 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; PortInterface::~PortInterface() { } struct Port::Private { Private(): count( 1 ), initialized( false ), port( 0 ) { } ~Private() { delete port; } void ref() { ++count; } bool deref() { return !--count; } unsigned int count; bool initialized; QString origin; QString name; QString version; ConcretePort *port; }; void Port::parsePkgName( const QString &pkgName, QString &name, QString &version ) { const int lastDash = pkgName.findRev( '-' ); name = pkgName.left( lastDash ); version = pkgName.mid( lastDash + 1 ); } Port Port::fromPkgName( const QString &origin, const QString &pkgName ) { QString name; QString version; parsePkgName( pkgName, name, version ); return Port( origin, name, version ); } Port::Port() : PortInterface(), d( 0 ) { } Port::Port( const Port &rhs ) : PortInterface(), d( new Private ) { *this = rhs; } Port::Port( const QString &origin ) : PortInterface(), d( new Private ) { d->origin = origin; } Port::Port( const QString &origin, const QString &name, const QString &version) : PortInterface(), d( new Private ) { d->origin = origin; d->name = name; d->version = version; } bool Port::operator==( const Port &rhs ) const { if ( !d || !rhs.d ) return d == rhs.d; return d->origin == rhs.d->origin; } bool Port::operator<( const Port &rhs ) const { if ( !d || !rhs.d ) return false; return d->origin < rhs.d->origin; } Port &Port::operator=( const Port &rhs ) { if ( this != &rhs ) { if ( rhs.d ) rhs.d->ref(); if ( d && d->deref() ) delete d; d = rhs.d; } return *this; } Port::~Port() { if ( d && d->deref() ) delete d; } QString Port::origin() const { Q_ASSERT( d ); return d->origin; } QString Port::name() const { Q_ASSERT( d ); if ( d->port ) return d->port->name(); if ( !d->initialized ) determineAttributes(); return d->name; } QString Port::version() const { Q_ASSERT( d ); if ( d->port ) return d->port->version(); if ( !d->initialized ) determineAttributes(); return d->version; } QString Port::installedVersion() const { Q_ASSERT( d ); initPort(); return d->port->installedVersion(); } QString Port::directory() const { Q_ASSERT( d ); initPort(); return d->port->directory(); } QString Port::prefix() const { Q_ASSERT( d ); initPort(); return d->port->prefix(); } QString Port::comment() const { Q_ASSERT( d ); initPort(); return d->port->comment(); } QString Port::description() const { Q_ASSERT( d ); initPort(); return d->port->description(); } QString Port::maintainer() const { Q_ASSERT( d ); initPort(); return d->port->maintainer(); } QStringList Port::categories() const { Q_ASSERT( d ); initPort(); return d->port->categories(); } PortList Port::buildDeps() const { Q_ASSERT( d ); initPort(); return d->port->buildDeps(); } PortList Port::runDeps() const { Q_ASSERT( d ); initPort(); return d->port->runDeps(); } QString Port::link() const { Q_ASSERT( d ); initPort(); return d->port->link(); } QStringList Port::files() const { Q_ASSERT( d ); initPort(); return d->port->files(); } QStringList Port::installedFiles() const { Q_ASSERT( d ); initPort(); return d->port->installedFiles(); } bool Port::installed() const { Q_ASSERT( d ); initPort(); return d->port->installed(); } long long Port::size() const { Q_ASSERT( d ); initPort(); return d->port->size(); } void Port::determineAttributes() const { QString pkgName = PortMgr::self().portDb().getEntry( d->origin ); pkgName = pkgName.left( pkgName.find( '|' ) ); parsePkgName( pkgName, d->name, d->version ); d->initialized = true; } void Port::initPort() const { if ( !d->port ) d->port = new ConcretePort( d->origin ); } // --------------------------------------------------------------------------- ConcretePort::ConcretePort( const QString &origin ) : PortInterface() { const QString description = PortMgr::self().portDb().getEntry( origin ); if ( !description.isNull() ) { // ### Error handling! const QStringList infoElements = QStringList::split( '|', description, true ); m_origin = origin; Port::parsePkgName( infoElements[ 0 ], m_name, m_version ); m_directory = infoElements[ 1 ]; m_prefix = infoElements[ 2 ]; m_comment = infoElements[ 3 ]; m_description = infoElements[ 4 ]; m_maintainer = infoElements[ 5 ]; m_categories = QStringList::split( ' ', infoElements[ 6 ] ); /* Some buggy ports belong twice to a single category, e.g. "editors editors russian". Work around that. */ m_categories = qUnique( m_categories ); m_buildDeps = parseDeps( infoElements[ 7 ] ); m_runDeps = parseDeps( infoElements[ 8 ] ); m_link = infoElements[ 9 ]; m_size = -1; } } QString ConcretePort::origin() const { return m_origin; } QString ConcretePort::name() const { return m_name; } QString ConcretePort::version() const { return m_version; } QString ConcretePort::installedVersion() const { const QString pkgName = PortMgr::self().pkgDb().getEntry( QString::fromLatin1( "?" ) + m_origin ); QString name, version; Port::parsePkgName( pkgName, name, version ); return version; } QString ConcretePort::directory() const { return m_directory; } QString ConcretePort::prefix() const { return m_prefix; } QString ConcretePort::comment() const { return m_comment; } QString ConcretePort::description() const { if ( !QFile::exists( m_description ) ) { KNotifyClient::event( QString::fromLatin1( "NoPortDescription" ), i18n( "The port %1-%2 doesn't seem to have a description, even " "though it's mandatory. Perhaps the port directory %3 isn't " "mounted properly?" ) .arg( name() ).arg( version() ).arg( PortMgr::self().portRootDir() ) ); return QString::null; } QFile f( m_description ); if ( !f.open( IO_ReadOnly ) ) return QString::null; QTextStream stream( &f ); return stream.read(); } QString ConcretePort::maintainer() const { return m_maintainer; } QStringList ConcretePort::categories() const { return m_categories; } PortList ConcretePort::runDeps() const { return m_runDeps; } PortList ConcretePort::buildDeps() const { return m_buildDeps; } QString ConcretePort::link() const { return m_link; } QStringList ConcretePort::files() const { return FileListRetriever::fileList( *this ); } QStringList ConcretePort::installedFiles() const { const QString pkgName = QString::fromLatin1( "%1-%2" ) .arg( name() ) .arg( installedVersion() ); const QString contentsFileName = PortMgr::self().pkgRootDir() + QString::fromLatin1( "/" ) + pkgName + QString::fromLatin1( "/+CONTENTS" ); QFile contentsFile( contentsFileName ); if ( !contentsFile.open( IO_ReadOnly ) ) { kdWarning() << "Could not open " << contentsFileName << endl; return QStringList(); } QStringList files; QTextStream stream( &contentsFile ); while ( !stream.atEnd() ) { QString line = stream.readLine(); if ( line[ 0 ] == '@' || line[ 0 ] == '+' ) continue; files += prefix() + QString::fromLatin1( "/" ) + line; } return files; } bool ConcretePort::installed() const { return !PortMgr::self().pkgDb().getEntry( QString::fromLatin1( "?" ) + m_origin ).isNull(); } long long ConcretePort::size() const { if ( m_size == -1 ) const_cast( this )->determineSize(); return m_size; } void ConcretePort::determineSize() { m_size = 0; const QStringList files_ = files(); QStringList::ConstIterator it = files_.begin(); QStringList::ConstIterator end = files_.end(); for ( ; it != end; ++it ) m_size += QFileInfo( *it ).size(); } PortList ConcretePort::parseDeps( const QString &depString ) const { PortList deps; const QStringList tokens = QStringList::split( ' ', depString ); QStringList::ConstIterator it = tokens.begin(); QStringList::ConstIterator end = tokens.end(); for ( ; it != end; ++it ) deps += Port::fromPkgName( PortMgr::self().portDb().getEntry( *it ), *it ); return deps; } // vim:ts=4:sw=4:noet:list