2015-09-07 19:36:45 +02:00
# include "./resolvebuildorder.h"
2015-08-19 02:13:28 +02:00
2015-12-25 01:58:19 +01:00
# include "./packagefinder.h"
2015-09-07 19:36:45 +02:00
# include "./manager.h"
# include "./config.h"
# include "./utilities.h"
2015-12-25 01:58:19 +01:00
# include "./repository.h"
2015-08-19 02:13:28 +02:00
# include <c++utilities/misc/memory.h>
2015-12-25 01:58:19 +01:00
# include <QStringBuilder>
2016-01-03 00:22:48 +01:00
# include <QEventLoop>
2015-12-25 01:58:19 +01:00
2015-08-19 02:13:28 +02:00
# 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
2016-01-03 00:22:48 +01:00
/*!
* \ brief The TaskInfo class defines a build task and provides the topo - sort required to resolve the build order .
*/
2015-08-19 02:13:28 +02:00
class TaskInfo
{
public :
2016-01-03 00:22:48 +01:00
TaskInfo ( const QString & name , bool onlyDependency = false , const QSet < TaskInfo * > & deps = QSet < TaskInfo * > ( ) ) ;
2015-08-19 02:13:28 +02:00
const QString & name ( ) const ;
2015-09-05 17:25:05 +02:00
void setName ( const QString & name ) ;
2016-01-03 00:22:48 +01:00
const QSet < TaskInfo * > deps ( ) const ;
2015-08-19 02:13:28 +02:00
void addDep ( TaskInfo * dep ) ;
2016-02-10 21:09:20 +01:00
bool areAllDepsAdded ( ) const ;
void setAllDepsAdded ( ) ;
2015-08-19 02:13:28 +02:00
bool isDone ( ) const ;
bool isVisited ( ) const ;
bool isOnlyDependency ( ) const ;
2015-12-25 01:58:19 +01:00
void setIsOnlyDependency ( bool isOnlyDependency ) ;
2016-01-18 19:50:05 +01:00
bool isBinaryAvailable ( ) const ;
void setBinaryAvailable ( bool binaryAvailable ) ;
2015-12-08 00:24:45 +01:00
bool isPackageRequested ( ) const ;
void setPackageRequested ( ) ;
2016-01-03 00:22:48 +01:00
QSet < Dependency > requiredFor ( ) const ;
void addRequiredFor ( const Dependency & dependency ) ;
2015-08-19 02:13:28 +02:00
void add ( QList < TaskInfo * > & results ) ;
2015-12-25 01:58:19 +01:00
Package * associatedPackage ( ) const ;
2016-01-03 00:22:48 +01:00
bool associatePackage ( Package * package ) ;
2015-08-19 02:13:28 +02:00
static void addAll ( const QList < TaskInfo * > & tasks , QList < TaskInfo * > & results ) ;
static TaskInfo * find ( const QList < TaskInfo * > & tasks , const QString & name ) ;
private :
QString m_name ;
2016-01-03 00:22:48 +01:00
QSet < TaskInfo * > m_deps ;
2016-02-10 21:09:20 +01:00
bool m_allDepsAdded ;
2015-08-19 02:13:28 +02:00
bool m_done ;
bool m_visited ;
bool m_onlyDep ;
2016-01-18 19:50:05 +01:00
bool m_binaryAvailable ;
2015-12-08 00:24:45 +01:00
bool m_pkgRequested ;
2016-01-03 00:22:48 +01:00
QSet < Dependency > m_requiredFor ;
2015-12-25 01:58:19 +01:00
Package * m_associatedPackage ;
2015-08-19 02:13:28 +02:00
} ;
2016-01-03 00:22:48 +01:00
/*!
* \ brief Constructs a new task .
*/
inline TaskInfo : : TaskInfo ( const QString & name , bool onlyDependency , const QSet < TaskInfo * > & deps ) :
2015-08-19 02:13:28 +02:00
m_name ( name ) ,
m_deps ( deps ) ,
2016-02-10 21:09:20 +01:00
m_allDepsAdded ( false ) ,
2015-08-19 02:13:28 +02:00
m_done ( false ) ,
m_visited ( false ) ,
2015-12-08 00:24:45 +01:00
m_onlyDep ( onlyDependency ) ,
2016-01-18 19:50:05 +01:00
m_binaryAvailable ( false ) ,
2015-12-25 01:58:19 +01:00
m_pkgRequested ( false ) ,
m_associatedPackage ( nullptr )
2015-08-19 02:13:28 +02:00
{ }
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns the name of the task .
*
* This is usually the name which has been specified when constructing
* the task . However , the name might be adjusted to the package name
* when a package is associated .
*/
2015-08-19 02:13:28 +02:00
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 ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns the dependencies added via addDep ( ) .
*/
inline const QSet < TaskInfo * > TaskInfo : : deps ( ) const
2015-08-19 02:13:28 +02:00
{
return m_deps ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Adds another task as dependency .
*/
2015-08-19 02:13:28 +02:00
inline void TaskInfo : : addDep ( TaskInfo * dep )
{
m_deps < < dep ;
}
2016-02-10 21:09:20 +01:00
/*!
* \ brief Returns whether setAllDepsAdded ( ) has been called for this task .
*/
bool TaskInfo : : areAllDepsAdded ( ) const
{
return m_allDepsAdded ;
}
/*!
* \ brief Sets that all dependencies have been added for this task .
*/
void TaskInfo : : setAllDepsAdded ( )
{
m_allDepsAdded = true ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns whether the task already has been added to the resulting list of tasks .
* \ sa add ( )
*/
2015-08-19 02:13:28 +02:00
inline bool TaskInfo : : isDone ( ) const
{
return m_done ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns whether the task has been visited .
* \ remarks Used to track circular dependencies ( within add ( ) ) .
*/
2015-08-19 02:13:28 +02:00
inline bool TaskInfo : : isVisited ( ) const
{
return m_visited ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns whether the task is only a dependency and none of the packages to be build .
* \ remarks Circular dependencies between packages which are only dependencies can be ignored .
*/
2015-08-19 02:13:28 +02:00
inline bool TaskInfo : : isOnlyDependency ( ) const
{
return m_onlyDep ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Sets whether the package is only a dependency .
* \ sa isOnlyDependency ( )
*/
2015-12-25 01:58:19 +01:00
inline void TaskInfo : : setIsOnlyDependency ( bool isOnlyDependency )
{
m_onlyDep = isOnlyDependency ;
}
2016-01-18 19:50:05 +01:00
/*!
* \ brief Returns whether a binary for the task is already available ( from previous build ) .
* \ remarks If a binary is available the resolver won ' t complain if this package is a
* cyclic dependency .
*/
inline bool TaskInfo : : isBinaryAvailable ( ) const
{
return m_binaryAvailable ;
}
/*!
* \ brief Sets whether a binary for the task is already available ( from previous build ) .
* \ sa isBinaryAvailable ( )
*/
inline void TaskInfo : : setBinaryAvailable ( bool binaryAvailable )
{
m_binaryAvailable = binaryAvailable ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns whether the package for this task has been requested yet .
*
* Used to avoid requesting the same package twice after the package
* couldn ' t be found when requesting it the first time .
*/
2015-12-08 00:24:45 +01:00
inline bool TaskInfo : : isPackageRequested ( ) const
{
return m_pkgRequested ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Sets whether the package has been requested .
*
* This is set just before a package for this task is requrested .
*/
2015-12-08 00:24:45 +01:00
inline void TaskInfo : : setPackageRequested ( )
{
m_pkgRequested = true ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns the dependencies the task has been added for .
* \ remarks
* - The same task can be added for multiple dependencies , eg .
* mingw - w64 - extra - cmake - modules and mingw - w64 - extra - cmake - modules = 5.15 .0 .
* - The dependencies must be set explicitely using addRequiredFor ( ) .
*/
inline QSet < Dependency > TaskInfo : : requiredFor ( ) const
{
return m_requiredFor ;
}
/*!
* \ brief Adds the specified \ a dependency to the list of dependencies the task has been added for .
* \ sa requiredFor ( )
*/
inline void TaskInfo : : addRequiredFor ( const Dependency & dependency )
{
m_requiredFor < < dependency ;
}
/*!
* \ brief Adds the task to the specified list of results . Ensures that all dependencies are added before .
* \ throws If a circular dependency between the build tasks has been detected , the causing task is thrown .
* \ remarks Dependencies must be added via addDep ( ) before calling this method .
*/
2015-08-19 02:13:28 +02:00
void TaskInfo : : add ( QList < TaskInfo * > & results )
{
2015-09-05 17:25:05 +02:00
if ( ! isDone ( ) ) {
if ( isVisited ( ) ) {
// cyclic dependency
2016-01-18 19:50:05 +01:00
if ( isOnlyDependency ( ) | | isBinaryAvailable ( ) ) {
2015-09-05 17:25:05 +02:00
// if this is only a dependency (which we don't want to build) don't care about it
2016-01-18 19:50:05 +01:00
// if there is already a binary (from previous build) don't care about it either
2015-09-05 17:25:05 +02:00
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
}
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns the package associated via associatePackage ( ) .
*/
2015-12-25 01:58:19 +01:00
inline Package * TaskInfo : : associatedPackage ( ) const
{
return m_associatedPackage ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Associates the specified \ a package with this build task .
*
* Does nothing if there is already a package assigned which matches all
* dependencies the task has been added for . Returns true in this case .
*
* Fails if the specified \ a package does not match all dependencies the task
* has been added for .
*
* \ return Returns whether either the currenlty assigned package or the specified
* \ a package matches all dependencies the task has been added for .
*/
bool TaskInfo : : associatePackage ( Package * package )
2015-12-25 01:58:19 +01:00
{
2016-01-03 00:22:48 +01:00
// check whether an appropriate package is already assigned
// and whether the package matches all dependencies this task is required for
bool assignmentRequired = ! m_associatedPackage , assignmentPossible = true ;
for ( const Dependency & dep : m_requiredFor ) {
if ( ! assignmentRequired & & ! m_associatedPackage - > matches ( dep ) ) {
assignmentRequired = true ;
}
if ( ! package - > matches ( dep ) ) {
assignmentPossible = false ;
}
}
if ( ! assignmentRequired ) {
return true ;
}
if ( ! assignmentPossible ) {
return false ;
}
2015-12-25 01:58:19 +01:00
m_associatedPackage = package ;
// update the name to ensure we have the acutal package name and not just a "provides" name
m_name = package - > name ( ) ;
2016-01-03 00:22:48 +01:00
return true ;
2015-12-25 01:58:19 +01:00
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Adds the specified \ a tasks and their dependencies to the specified list of results . Ensures that all
* tasks are added in the right order .
* \ throws If a circular dependency between the build tasks has been detected , the causing task is thrown .
* \ remarks Dependencies must be added to the \ a tasks via addDep ( ) before calling this method .
*/
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
}
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Finds the task with the specified \ a name in the specified list of \ a tasks .
* \ remarks Does not search dependencies the list does not contain .
*/
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 ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ class BuildOrderResolver
* \ brief The BuildOrderResolver class resolves the build order for a specified array of packages .
*
* Resolving the build order is done in the following steps :
* 1. instantiation : initial tasks are added
* 2. findDependencies ( ) : dependencies for each task are added , some packages might have to be requested first
* 3. if some packages must be requested : wait for requested packages , if requested packages are available , go to 2.
* 4. all dependencies are added : signal ready ( ) is emitted
* 5. resolve ( ) : build order is resolved , either resolvingFinished ( ) or resolvingFailed ( ) is emitted
*/
2015-08-19 02:13:28 +02:00
2016-01-03 00:22:48 +01:00
/*!
* \ brief Creates a new BuildOrderResolver using the specified \ a manager .
*/
2016-02-20 03:00:34 +01:00
BuildOrderResolver : : BuildOrderResolver ( Manager & manager , bool addSourceOnlyDeps , bool requireSources ) :
2015-12-25 01:58:19 +01:00
m_manager ( manager ) ,
m_finder ( nullptr ) ,
2016-01-03 00:22:48 +01:00
m_addSourceOnlyDeps ( addSourceOnlyDeps ) ,
2016-02-20 03:00:34 +01:00
m_requireSources ( requireSources ) ,
2016-01-03 00:22:48 +01:00
m_hasFinished ( false )
{ }
/*!
* \ brief Adds the specified \ a errorMessage .
*/
void BuildOrderResolver : : addError ( const QString & errorMessage )
2015-08-19 02:13:28 +02:00
{
2016-01-03 00:22:48 +01:00
if ( ! m_errorMessage . isEmpty ( ) ) {
m_errorMessage . append ( QStringLiteral ( " \u2192 " ) ) ;
2015-12-25 01:58:19 +01:00
}
2016-01-03 00:22:48 +01:00
m_errorMessage . append ( errorMessage ) ;
2015-12-25 01:58:19 +01:00
}
2015-12-08 00:24:45 +01:00
2016-01-03 00:22:48 +01:00
/*!
* \ brief Destroys the object .
*/
2015-12-25 01:58:19 +01:00
BuildOrderResolver : : ~ BuildOrderResolver ( )
{
qDeleteAll ( m_tasks ) ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Finds the dependencies of all packages .
*
* Also internally called after requested packages are available .
*/
2015-12-25 01:58:19 +01:00
void BuildOrderResolver : : findDependencies ( )
{
// find specified packages and their dependencies
for ( int i = 0 , size = m_tasks . size ( ) ; i ! = size ; + + i ) {
2016-02-10 21:09:20 +01:00
if ( ! addDependenciesToTask ( m_tasks [ i ] ) ) {
2016-01-03 00:22:48 +01:00
return ;
}
2015-12-25 01:58:19 +01:00
}
// request dependencies to be requested
requestDependenciesToBeRequested ( ) ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns the resulting build order .
* \ remarks Build order must have been resolved yet .
*/
2015-12-25 01:58:19 +01:00
QStringList BuildOrderResolver : : resultNames ( )
{
QStringList names ;
names . reserve ( m_results . size ( ) ) ;
for ( const auto * res : m_results ) {
names < < res - > name ( ) ;
}
return names ;
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Prints relevant packages .
* \ remarks All dependencies must have been found yet .
*/
2015-12-25 01:58:19 +01:00
void BuildOrderResolver : : printRelevantPackages ( )
{
cerr < < shchar < < " Relevant packages: " ;
for ( const auto * task : m_tasks ) {
cerr < < ' ' < < task - > name ( ) . toLocal8Bit ( ) . data ( ) ;
2015-08-19 02:13:28 +02:00
}
2015-12-25 01:58:19 +01:00
cerr < < endl ;
2015-08-19 02:13:28 +02:00
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Prints the resulting build order .
* \ remarks Build order must have been resolved yet .
*/
2015-12-25 01:58:19 +01:00
void BuildOrderResolver : : printResults ( )
2015-09-07 19:36:45 +02:00
{
if ( useShSyntax ) {
2015-12-25 01:58:19 +01:00
Utilities : : printBashArray ( cout , " REPOINDEX_RESULTS " , resultNames ( ) ) ;
2015-09-07 19:36:45 +02:00
} else {
2015-12-25 01:58:19 +01:00
Utilities : : printValues ( cout , " Results " , resultNames ( ) ) ;
}
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Resolves the build order .
* \ remarks All dependencies must have been found yet .
*
* Emits either resolvingFinished ( ) or resolvingFailed ( ) depending on whether
* the operation succeeded .
*/
2015-12-25 01:58:19 +01:00
void BuildOrderResolver : : resolve ( )
{
try {
m_results . clear ( ) ;
m_results . reserve ( m_tasks . size ( ) ) ;
TaskInfo : : addAll ( m_tasks , m_results ) ;
2016-01-03 00:22:48 +01:00
m_hasFinished = true ;
2015-12-25 01:58:19 +01:00
emit resolvingFinished ( ) ;
} catch ( const TaskInfo & cyclic ) {
2016-01-03 00:22:48 +01:00
addError ( QStringLiteral ( " Can't resolve build order; the package " ) % cyclic . name ( ) % QStringLiteral ( " is a cyclic dependency. " ) ) ;
m_hasFinished = true ;
emit resolvingFailed ( m_errorMessage ) ;
2015-12-25 01:58:19 +01:00
}
}
2016-01-03 00:22:48 +01:00
/*!
* \ brief Returns the package for the specified \ a dependency or nullptr if no package could be found .
*/
2016-02-10 21:09:20 +01:00
Package * BuildOrderResolver : : findPackageForDependency ( const Dependency & dependency , bool sourceRequired )
2015-12-25 01:58:19 +01:00
{
Package * pkg ;
2016-02-10 21:09:20 +01:00
if ( ! sourceRequired & & ( pkg = m_manager . packageProviding ( dependency ) ) ) {
2015-12-25 01:58:19 +01:00
return pkg ;
} else if ( m_finder & & ( pkg = m_finder - > packageProviding ( dependency ) ) ) {
return pkg ;
2015-09-07 19:36:45 +02:00
}
2015-12-25 01:58:19 +01:00
return nullptr ;
2015-09-07 19:36:45 +02:00
}
2015-12-08 00:24:45 +01:00
/*!
2016-01-03 00:22:48 +01:00
* \ brief Finds the package for the specified \ a task and then adds dependencies recursively .
2015-12-08 00:24:45 +01:00
*/
2015-12-25 01:58:19 +01:00
bool BuildOrderResolver : : addDependenciesToTask ( TaskInfo * task )
2015-08-19 02:13:28 +02:00
{
2015-12-25 01:58:19 +01:00
// check whether dependencies have already been added
2016-02-10 21:09:20 +01:00
if ( task - > areAllDepsAdded ( ) ) {
2015-12-25 01:58:19 +01:00
// package associated -> dependencies already added
return true ;
}
2015-12-08 00:24:45 +01:00
Dependency dep ( task - > name ( ) , QString ( ) ) ;
2016-02-20 03:00:34 +01:00
if ( const auto pkg = findPackageForDependency ( dep , m_requireSources & & ! task - > isOnlyDependency ( ) ) ) {
2016-01-03 00:22:48 +01:00
task - > addRequiredFor ( dep ) ;
if ( task - > associatePackage ( pkg ) ) {
2016-01-18 19:50:05 +01:00
if ( pkg - > repository ( ) - > isSourceOnly ( ) ) {
if ( m_addSourceOnlyDeps ) {
task - > setIsOnlyDependency ( false ) ;
}
} else {
task - > setBinaryAvailable ( true ) ;
2016-01-03 00:22:48 +01:00
}
// add dependencies to task
2016-02-10 21:09:20 +01:00
task - > setAllDepsAdded ( ) ;
2016-01-03 00:22:48 +01:00
if ( ! addDependenciesToTask ( task , pkg - > allDependencies ( ) ) ) {
addError ( QStringLiteral ( " Can not add dependencies of the dependency \" " ) % dep . toString ( ) % QStringLiteral ( " \" . " ) ) ;
m_hasFinished = true ;
emit resolvingFailed ( errorMessage ( ) ) ;
return false ;
}
} else {
addError ( QStringLiteral ( " Can not associate the task \" " ) % task - > name ( ) % QStringLiteral ( " \" with the package required by dependency \" " ) % dep . toString ( ) % QStringLiteral ( " \" . " ) ) ;
m_hasFinished = true ;
emit resolvingFailed ( errorMessage ( ) ) ;
return false ;
2015-12-25 01:58:19 +01:00
}
2015-12-08 00:24:45 +01:00
} else if ( ! task - > isPackageRequested ( ) ) {
task - > setPackageRequested ( ) ;
m_dependenciesToBeRequested < < dep ;
2015-08-19 02:13:28 +02:00
} else {
2016-01-03 00:22:48 +01:00
addError ( QStringLiteral ( " The specified package \" " ) % task - > name ( ) % QStringLiteral ( " \" could not be found. " ) ) ;
m_hasFinished = true ;
emit resolvingFailed ( errorMessage ( ) ) ;
2015-12-25 01:58:19 +01:00
return false ;
2015-08-19 02:13:28 +02:00
}
2015-12-25 01:58:19 +01:00
return true ;
2015-08-19 02:13:28 +02:00
}
2015-12-08 00:24:45 +01:00
/*!
* \ brief Finds packages for the the specified \ a dependencies and adds them to the specified \ a task .
2016-01-03 00:22:48 +01:00
* \ remarks Adds dependencies of the dependencies recursively .
2015-12-08 00:24:45 +01:00
*/
2016-01-03 00:22:48 +01:00
bool BuildOrderResolver : : addDependenciesToTask ( TaskInfo * task , const QList < const QList < Dependency > * > & dependencies )
2015-08-19 02:13:28 +02:00
{
2016-01-03 00:22:48 +01:00
for ( auto * deps : dependencies ) {
for ( auto & dep : * deps ) {
auto * depTask = TaskInfo : : find ( m_tasks , dep . name ) ;
2016-02-20 03:00:34 +01:00
auto * depPkg = findPackageForDependency ( dep , m_requireSources & & depTask & & ! depTask - > isOnlyDependency ( ) ) ;
2016-02-10 21:09:20 +01:00
const QString taskName = depPkg ? depPkg - > name ( ) : dep . name ;
2016-01-03 00:22:48 +01:00
bool newTask ;
if ( depTask ) {
// we've already added a task for this dependency
newTask = false ;
} else {
// create new task
m_tasks < < ( depTask = new TaskInfo ( taskName , true ) ) ;
newTask = true ;
}
// add dependency task to the dependencies of "parent" task
2015-12-25 01:58:19 +01:00
task - > addDep ( depTask ) ;
2016-01-03 00:22:48 +01:00
depTask - > addRequiredFor ( dep ) ;
2015-12-25 01:58:19 +01:00
if ( depPkg ) {
2016-01-03 00:22:48 +01:00
if ( depTask - > associatePackage ( depPkg ) ) {
2016-01-18 19:50:05 +01:00
if ( depPkg - > repository ( ) - > isSourceOnly ( ) ) {
if ( m_addSourceOnlyDeps ) {
depTask - > setIsOnlyDependency ( false ) ;
}
} else {
depTask - > setBinaryAvailable ( true ) ;
2016-01-03 00:22:48 +01:00
}
2016-02-10 21:09:20 +01:00
if ( ! depTask - > areAllDepsAdded ( ) ) {
2016-01-03 00:22:48 +01:00
// add dependencies of the dependency
2016-02-10 21:09:20 +01:00
depTask - > setAllDepsAdded ( ) ;
2016-01-03 00:22:48 +01:00
if ( ! addDependenciesToTask ( depTask , depPkg - > allDependencies ( ) ) ) {
addError ( QStringLiteral ( " Can not add dependencies of the dependency \" " ) % dep . toString ( ) % QStringLiteral ( " \" . " ) ) ;
return false ;
}
}
} else {
addError ( QStringLiteral ( " Can not associate the task \" " ) % depTask - > name ( ) % QStringLiteral ( " \" with the package required by dependency \" " ) % dep . toString ( ) % QStringLiteral ( " \" . " ) ) ;
return false ;
2015-12-25 01:58:19 +01:00
}
} else {
2016-01-03 00:22:48 +01:00
if ( ! m_dependenciesToBeRequested . contains ( dep ) ) {
if ( ! depTask - > isPackageRequested ( ) ) {
depTask - > setPackageRequested ( ) ;
m_dependenciesToBeRequested < < dep ;
} else {
addError ( QStringLiteral ( " The specified package \" " ) % dep . toString ( ) % QStringLiteral ( " \" could not be found. " ) ) ;
return false ;
}
}
2015-12-25 01:58:19 +01:00
}
}
}
return true ;
}
/*!
* \ brief Requests dependencies to be requested .
*/
void BuildOrderResolver : : requestDependenciesToBeRequested ( )
{
// check whether there are dependencies to be requested
if ( ! m_dependenciesToBeRequested . isEmpty ( ) ) {
// print dependencies to be requested
if ( m_manager . config ( ) . isVerbose ( ) ) {
cerr < < shchar < < " Dependencies to be requested: " ;
for ( const Dependency & dep : m_dependenciesToBeRequested ) {
cerr < < ' ' < < dep . name . toStdString ( ) ;
}
cerr < < endl ;
}
// do requests (using package finder)
2016-02-10 21:09:20 +01:00
m_finder = make_unique < PackageFinder > ( m_manager , m_dependenciesToBeRequested , true ) ;
2015-12-25 01:58:19 +01:00
// all dependencies requested -> clear dependencies to be requested
m_dependenciesToBeRequested . clear ( ) ;
// add results
if ( m_finder - > areAllResultsAvailable ( ) ) {
// results are immediately available (already cached)
2016-01-03 00:22:48 +01:00
findDependencies ( ) ;
2015-09-05 17:25:05 +02:00
} else {
2015-12-25 01:58:19 +01:00
// need to request actually
2016-01-03 00:22:48 +01:00
connect ( m_finder . get ( ) , & PackageFinder : : resultsAvailable , this , & BuildOrderResolver : : findDependencies ) ;
2015-09-05 17:25:05 +02:00
}
2015-12-25 01:58:19 +01:00
} else {
// there are no dependencies to be requested -> ready to resolve build order
emit ready ( ) ;
2015-08-19 02:13:28 +02:00
}
}
2016-01-03 00:22:48 +01:00
/*!
* \ class BuildOrderResolverCli
* \ brief The BuildOrderResolverCli class resolves the build order of the specified packages and prints the results stdout .
*/
/*!
* \ brief Creates a new BuildOrderResolverCli for the specified \ a packages using the specified \ a manager .
*/
2016-05-26 02:29:56 +02:00
BuildOrderResolverCli : : BuildOrderResolverCli ( Manager & manager , const std : : vector < const char * > & packages , bool addSourceOnlyDeps , bool requireSources ) :
2016-02-20 03:00:34 +01:00
BuildOrderResolver ( manager , addSourceOnlyDeps , requireSources )
2016-01-03 00:22:48 +01:00
{
cerr < < shchar < < " Getting package information ... " < < endl ;
tasks ( ) . clear ( ) ;
tasks ( ) . reserve ( packages . size ( ) * 2 ) ;
// add a task for each specified package
2016-05-26 02:29:56 +02:00
for ( const char * pkgName : packages ) {
tasks ( ) < < new TaskInfo ( QString : : fromLocal8Bit ( pkgName ) ) ;
2016-01-03 00:22:48 +01:00
}
}
/*!
* \ brief Determines dependencies , prints relevant packages , resolves build order , prints results / errors .
* \ remarks Does not return until everything is done .
*/
int BuildOrderResolverCli : : exec ( )
{
if ( manager ( ) . config ( ) . isVerbose ( ) ) {
connect ( this , & BuildOrderResolver : : ready , this , & BuildOrderResolver : : printRelevantPackages ) ;
}
connect ( this , & BuildOrderResolver : : ready , this , & BuildOrderResolver : : resolve ) ;
connect ( this , & BuildOrderResolver : : resolvingFinished , this , & BuildOrderResolver : : printResults ) ;
connect ( this , & BuildOrderResolver : : resolvingFailed , static_cast < void ( * ) ( const QString & ) > ( Utilities : : printError ) ) ;
QEventLoop loop ;
connect ( this , & BuildOrderResolver : : resolvingFinished , & loop , & QEventLoop : : quit ) ;
connect ( this , & BuildOrderResolver : : resolvingFailed , & loop , & QEventLoop : : quit ) ;
findDependencies ( ) ;
if ( hasFinished ( ) ) {
// resolving might have been finished immidiately
return errorMessage ( ) . isEmpty ( ) ;
} else {
// resolving not finished yet (deps must be requested)
return loop . exec ( ) ;
}
}
2015-08-19 02:13:28 +02:00
} // namespace PackageManagement