2015-08-19 02:13:28 +02:00
# include "resolvebuildorder.h"
# include "manager.h"
# include "config.h"
# include <c++utilities/misc/memory.h>
# include <iostream>
# include <sstream>
using namespace std ;
using namespace ApplicationUtilities ;
namespace PackageManagement {
class TaskInfo
{
public :
TaskInfo ( QString name , bool onlyDependency = false , const QList < TaskInfo * > & deps = QList < TaskInfo * > ( ) ) ;
const QString & name ( ) const ;
const QList < TaskInfo * > deps ( ) const ;
void addDep ( TaskInfo * dep ) ;
bool isDone ( ) const ;
bool isVisited ( ) const ;
bool isOnlyDependency ( ) const ;
void add ( QList < TaskInfo * > & results ) ;
static void addAll ( const QList < TaskInfo * > & tasks , QList < TaskInfo * > & results ) ;
static TaskInfo * find ( const QList < TaskInfo * > & tasks , const QString & name ) ;
private :
QString m_name ;
QList < TaskInfo * > m_deps ;
bool m_done ;
bool m_visited ;
bool m_onlyDep ;
} ;
inline TaskInfo : : TaskInfo ( QString name , bool onlyDependency , const QList < TaskInfo * > & deps ) :
m_name ( name ) ,
m_deps ( deps ) ,
m_done ( false ) ,
m_visited ( false ) ,
m_onlyDep ( onlyDependency )
{ }
inline const QString & TaskInfo : : name ( ) const
{
return m_name ;
}
inline const QList < TaskInfo * > TaskInfo : : deps ( ) const
{
return m_deps ;
}
inline void TaskInfo : : addDep ( TaskInfo * dep )
{
m_deps < < dep ;
}
inline bool TaskInfo : : isDone ( ) const
{
return m_done ;
}
inline bool TaskInfo : : isVisited ( ) const
{
return m_visited ;
}
inline bool TaskInfo : : isOnlyDependency ( ) const
{
return m_onlyDep ;
}
void TaskInfo : : add ( QList < TaskInfo * > & results )
{
if ( ! m_done ) {
if ( m_visited ) {
throw * this ; // cyclic dependency
} else {
m_visited = true ;
}
for ( auto * dep : m_deps ) {
dep - > add ( results ) ;
}
m_done = true ;
results < < this ;
}
}
void TaskInfo : : addAll ( const QList < TaskInfo * > & tasks , QList < TaskInfo * > & results )
{
for ( auto * task : tasks ) {
if ( ! task - > m_done ) {
task - > add ( results ) ;
}
}
}
TaskInfo * TaskInfo : : find ( const QList < TaskInfo * > & tasks , const QString & name )
{
for ( auto * task : tasks ) {
if ( task - > name ( ) = = name ) {
return task ;
}
}
return nullptr ;
}
template < class ListType >
class DestroyList
{
public :
DestroyList ( ListType & list ) :
m_list ( list )
{ }
~ DestroyList ( )
{
qDeleteAll ( m_list ) ;
}
private :
ListType & m_list ;
} ;
BuildOrderResolver : : BuildOrderResolver ( const Manager & manager ) :
m_manager ( manager )
{ }
QStringList BuildOrderResolver : : resolve ( const StringVector & packages ) const
{
cerr < < " Getting package information ... " < < endl ;
QList < TaskInfo * > tasks ;
tasks . reserve ( packages . size ( ) ) ;
try {
// add a task for each specified package
for ( const auto & pkgName : packages ) {
tasks < < new TaskInfo ( QString : : fromLocal8Bit ( pkgName . data ( ) ) ) ;
}
// find specified packages and their dependencies
for ( auto * task : tasks ) {
addDeps ( tasks , task ) ;
}
cerr < < " Relevant packages: " ;
for ( const auto * task : tasks ) {
cerr < < task - > name ( ) . toLocal8Bit ( ) . data ( ) < < ' ' ;
}
cerr < < endl ;
// topo sort
QList < TaskInfo * > results ;
results . reserve ( tasks . size ( ) ) ;
try {
TaskInfo : : addAll ( tasks , results ) ;
QStringList names ;
names . reserve ( results . size ( ) ) ;
for ( const auto * res : results ) {
names < < res - > name ( ) ;
}
return names ;
} catch ( const TaskInfo & cyclic ) {
throw runtime_error ( " Can't resolve build order; the package " + cyclic . name ( ) . toStdString ( ) + " is a cyclic dependency. " ) ;
}
} catch ( . . . ) {
qDeleteAll ( tasks ) ;
throw ;
}
}
void BuildOrderResolver : : addDeps ( QList < TaskInfo * > & tasks , TaskInfo * task ) const
{
if ( const auto pkg = m_manager . packageFromSyncDataBases ( task - > name ( ) . toLocal8Bit ( ) . data ( ) ) ) {
2015-09-04 14:37:01 +02:00
for ( auto dep : pkg - > dependencies ( ) ) {
if ( auto * depTask = addDep ( tasks , dep . name ) ) {
2015-08-19 02:13:28 +02:00
task - > addDep ( depTask ) ;
}
}
} else {
stringstream ss ;
ss < < " The package \" " < < task - > name ( ) . toLocal8Bit ( ) . data ( ) < < " \" could not be found; TODO: search AUR for package, add AUR deps to the packages we want to build " ;
throw runtime_error ( ss . str ( ) ) ;
}
}
2015-09-04 14:37:01 +02:00
TaskInfo * BuildOrderResolver : : addDep ( QList < TaskInfo * > & tasks , const QString & depName ) const
2015-08-19 02:13:28 +02:00
{
if ( auto * task = TaskInfo : : find ( tasks , depName ) ) {
// we've already added a task for this dependency
return task ;
} else {
// create new task
//task = new TaskInfo(QString::fromLocal8Bit(depName));
//tasks << task;
//return task;
return nullptr ;
}
}
} // namespace PackageManagement