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 ;
2015-09-05 17:25:05 +02:00
namespace RepoIndex {
2015-08-19 02:13:28 +02:00
class TaskInfo
{
public :
TaskInfo ( QString name , bool onlyDependency = false , const QList < TaskInfo * > & deps = QList < TaskInfo * > ( ) ) ;
const QString & name ( ) const ;
2015-09-05 17:25:05 +02:00
void setName ( const QString & name ) ;
2015-08-19 02:13:28 +02:00
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 ;
}
2015-09-05 17:25:05 +02:00
inline void TaskInfo : : setName ( const QString & name )
{
m_name = name ;
}
2015-08-19 02:13:28 +02:00
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 )
{
2015-09-05 17:25:05 +02:00
if ( ! isDone ( ) ) {
if ( isVisited ( ) ) {
// cyclic dependency
if ( isOnlyDependency ( ) ) {
// if this is only a dependency (which we don't want to build) don't care about it
return ;
} else {
throw * this ;
}
2015-08-19 02:13:28 +02:00
} else {
m_visited = true ;
}
2015-09-05 17:25:05 +02:00
for ( auto * dep : deps ( ) ) {
2015-08-19 02:13:28 +02:00
dep - > add ( results ) ;
}
m_done = true ;
2015-09-05 17:25:05 +02:00
if ( ! isOnlyDependency ( ) ) {
results < < this ;
}
2015-08-19 02:13:28 +02:00
}
}
void TaskInfo : : addAll ( const QList < TaskInfo * > & tasks , QList < TaskInfo * > & results )
{
for ( auto * task : tasks ) {
2015-09-05 17:25:05 +02:00
task - > add ( results ) ;
2015-08-19 02:13:28 +02:00
}
}
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
{
2015-09-05 17:25:05 +02:00
cerr < < shchar < < " Getting package information ... " < < endl ;
2015-08-19 02:13:28 +02:00
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
2015-09-05 17:25:05 +02:00
for ( int i = 0 , size = tasks . size ( ) ; i ! = size ; + + i ) {
addDeps ( tasks , tasks . at ( i ) ) ;
2015-08-19 02:13:28 +02:00
}
2015-09-05 17:25:05 +02:00
if ( m_manager . config ( ) . isVerbose ( ) ) {
cerr < < shchar < < " Relevant packages: " ;
for ( const auto * task : tasks ) {
cerr < < task - > name ( ) . toLocal8Bit ( ) . data ( ) < < ' ' ;
}
cerr < < endl ;
2015-08-19 02:13:28 +02:00
}
// topo sort
QList < TaskInfo * > results ;
try {
2015-09-05 17:25:05 +02:00
results . reserve ( packages . size ( ) ) ;
2015-08-19 02:13:28 +02:00
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
{
2015-09-05 17:25:05 +02:00
if ( const auto pkg = m_manager . packageProviding ( Dependency ( task - > name ( ) ) ) ) {
task - > setName ( pkg - > name ( ) ) ; // update the name to ensure we have the acutal package name and not just a "provides" name
addDeps ( tasks , task , pkg - > dependencies ( ) ) ;
2015-08-19 02:13:28 +02:00
} else {
stringstream ss ;
2015-09-05 17:25:05 +02:00
ss < < " The specified package \" " < < task - > name ( ) . toLocal8Bit ( ) . data ( ) < < " \" could not be found; TODO: search AUR for package, add AUR deps to the packages we want to build " ;
2015-08-19 02:13:28 +02:00
throw runtime_error ( ss . str ( ) ) ;
}
}
2015-09-05 17:25:05 +02:00
void BuildOrderResolver : : addDeps ( QList < TaskInfo * > & tasks , TaskInfo * task , const QList < Dependency > & dependencies ) const
2015-08-19 02:13:28 +02:00
{
2015-09-05 17:25:05 +02:00
for ( auto & dep : dependencies ) {
if ( const auto depPkg = m_manager . packageProviding ( dep ) ) {
auto * depTask = TaskInfo : : find ( tasks , depPkg - > name ( ) ) ;
if ( depTask ) {
// we've already added a task for this dependency
// adds dependency task to the dependencies of "parent" task
task - > addDep ( depTask ) ;
} else {
// create new task
tasks < < ( depTask = new TaskInfo ( depPkg - > name ( ) , true ) ) ;
// adds dependency task to the dependencies of "parent" task
task - > addDep ( depTask ) ;
// add dependencies of the dependency
addDeps ( tasks , depTask , depPkg - > dependencies ( ) ) ;
}
} else {
stringstream ss ;
ss < < " The dependency \" " < < dep . 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-08-19 02:13:28 +02:00
}
}
} // namespace PackageManagement