/*
* port.cc
*
* Copyright (c) 2002, 2003 Frerich Raabe <raabe@kde.org>
*
* 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 <kdebug.h>
#include <klocale.h>
#include <knotifyclient.h>
#include <qdir.h>
#include <stdlib.h> // 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 <class Container>
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<ConcretePort *>( 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
syntax highlighted by Code2HTML, v. 0.9.1