203 lines
4.8 KiB
C++
203 lines
4.8 KiB
C++
#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())) {
|
|
for(auto dep : pkg->dependencies()) {
|
|
if(auto *depTask = addDep(tasks, dep.name)) {
|
|
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());
|
|
}
|
|
}
|
|
|
|
TaskInfo *BuildOrderResolver::addDep(QList<TaskInfo *> &tasks, const QString &depName) const
|
|
{
|
|
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
|
|
|