#include "./resolvebuildorder.h" #include "./manager.h" #include "./config.h" #include "./utilities.h" #include #include #include using namespace std; using namespace ApplicationUtilities; namespace RepoIndex { class TaskInfo { public: TaskInfo(QString name, bool onlyDependency = false, const QList &deps = QList()); const QString &name() const; void setName(const QString &name); const QList deps() const; void addDep(TaskInfo *dep); bool isDone() const; bool isVisited() const; bool isOnlyDependency() const; void add(QList &results); static void addAll(const QList &tasks, QList &results); static TaskInfo *find(const QList &tasks, const QString &name); private: QString m_name; QList m_deps; bool m_done; bool m_visited; bool m_onlyDep; }; inline TaskInfo::TaskInfo(QString name, bool onlyDependency, const QList &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 void TaskInfo::setName(const QString &name) { m_name = name; } inline const QList 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 &results) { 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; } } else { m_visited = true; } for(auto *dep : deps()) { dep->add(results); } m_done = true; if(!isOnlyDependency()) { results << this; } } } void TaskInfo::addAll(const QList &tasks, QList &results) { for(auto *task : tasks) { task->add(results); } } TaskInfo *TaskInfo::find(const QList &tasks, const QString &name) { for(auto *task : tasks) { if(task->name() == name) { return task; } } return nullptr; } template 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 << shchar << "Getting package information ..." << endl; QList 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(int i = 0, size = tasks.size(); i != size; ++i) { // addDeps(tasks, tasks.at(i)); //} for(auto *task : tasks) { addDeps(tasks, task); } if(m_manager.config().isVerbose()) { cerr << shchar << "Relevant packages: "; for(const auto *task : tasks) { cerr << task->name().toLocal8Bit().data() << ' '; } cerr << endl; } // topo sort QList results; try { results.reserve(packages.size()); 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::printResults(const QStringList &results) { if(useShSyntax) { Utilities::printBashArray(cout, "REPOINDEX_RESULTS", results); } else { Utilities::printValues(cout, "Results", results); } } void BuildOrderResolver::addDeps(QList &tasks, TaskInfo *task) const { if(const auto pkg = m_manager.packageProviding(Dependency(task->name(), QString()))) { 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()); } else { stringstream ss; 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"; throw runtime_error(ss.str()); } } void BuildOrderResolver::addDeps(QList &tasks, TaskInfo *task, const QList &dependencies) const { 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()); } } } } // namespace PackageManagement