fixed bug causing duplicate entries when searching AUR

This commit is contained in:
Martchus 2015-12-08 00:24:45 +01:00
parent 6e36370716
commit 1356901224
18 changed files with 217 additions and 67 deletions

View File

@ -45,7 +45,7 @@ AlpmPackage::AlpmPackage(alpm_pkg_t *package, AlpmDatabase *alpmDatabase) :
m_ptr(package)
{
m_origin = static_cast<PackageOrigin>(alpm_pkg_get_origin(package));
m_hasGeneralInfo = m_hasBuildRelatedMetaData = m_hasInstallRelatedMetaData = true;
m_hasGeneralInfo = m_hasAllGeneralInfo = m_hasBuildRelatedMetaData = m_hasInstallRelatedMetaData = true;
m_version = qstr(alpm_pkg_get_version(package));
m_description = qstr(alpm_pkg_get_desc(package));
m_upstreamUrl = qstr(alpm_pkg_get_url(package));

View File

@ -146,18 +146,17 @@ unique_ptr<AlpmOwnershipPackage> Manager::packageFromFile(const char *fileName,
}
/*!
* \brief Returns the first package satisfiing the specified dependency from one of the available package sources (excluding the local database).
* \brief Returns the first package satisfiing the specified dependency from one of the available package sources (excluding the local database
* and sources requirering requests such as the AUR).
*/
Package *Manager::packageProviding(const Dependency &dependency)
{
for(auto &dbEntry : syncDatabases()) {
QReadLocker locker(dbEntry.second->lock());
if(auto *pkg = dbEntry.second->packageProviding(dependency)) {
return pkg;
}
}
if(config().isAurEnabled()) {
// TODO: check AUR
}
return nullptr;
}
@ -168,6 +167,7 @@ Package *Manager::packageProviding(const Dependency &dependency)
const Package *Manager::packageProviding(const Dependency &dependency) const
{
for(const auto &dbEntry : syncDatabases()) {
QReadLocker locker(dbEntry.second->lock());
if(const auto *pkg = dbEntry.second->packageProviding(dependency)) {
return pkg;
}

View File

@ -35,6 +35,7 @@ Package::Package(const QString &name, Repository *repository) :
m_repository(repository),
m_timeStamp(DateTime::now()),
m_hasGeneralInfo(false),
m_hasAllGeneralInfo(false),
m_name(name),
m_requiredByComputed(false),
m_hasInstallScript(false),
@ -124,9 +125,6 @@ void Package::computeRequiredBy(Manager &manager)
bool Package::matches(const QString &name, const QString &version, const Dependency &dependency)
{
if(name == QStringLiteral("gst-plugins-base-libs") && dependency.name == QStringLiteral("gst-plugins-base-libs")) {
dependency.name.begin();
}
if(name == dependency.name) {
PackageVersionComparsion cmp;
switch(dependency.mode) {
@ -324,7 +322,7 @@ void Package::writeToCacheStream(QDataStream &out)
{
out << static_cast<qint32>(m_origin) << m_timeStamp;
// general info
out << m_hasGeneralInfo << m_name << m_version << m_description << m_upstreamUrl << m_licenses
out << m_hasGeneralInfo << m_hasAllGeneralInfo << m_name << m_version << m_description << m_upstreamUrl << m_licenses
<< m_groups << m_dependencies << m_optionalDependencies << m_conflicts << m_provides
<< m_replaces << m_requiredByComputed << m_requiredBy << m_optionalFor << m_hasInstallScript;
// build related meta data
@ -357,7 +355,7 @@ void Package::restoreFromCacheStream(QDataStream &in)
m_origin = static_cast<PackageOrigin>(tmp); // TODO: validate value
in >> m_timeStamp;
// general info
in >> m_hasGeneralInfo >> m_name >> m_version >> m_description >> m_upstreamUrl >> m_licenses
in >> m_hasGeneralInfo >> m_hasAllGeneralInfo >> m_name >> m_version >> m_description >> m_upstreamUrl >> m_licenses
>> m_groups >> m_dependencies >> m_optionalDependencies >> m_conflicts >> m_provides
>> m_replaces >> m_requiredByComputed >> m_requiredBy >> m_optionalFor >> m_hasInstallScript;
// build related meta data
@ -388,7 +386,7 @@ void Package::restoreFromCacheStream(QDataStream &in)
}
/*!
* \brief Puts the specified src/pkg info key value pairs; clears current dependencies, provides, ...
* \brief Puts the specified src/pkg info key value pairs; clears current dependencies, provides, ... before inserting new values.
* \remarks This method should only be called by the associated repository because it must handle a possible name change.
*/
void Package::putInfo(const QList<QPair<QString, QString> > &baseInfo, const QList<QPair<QString, QString> > &pkgInfo)
@ -453,6 +451,8 @@ void Package::putInfo(const QList<QPair<QString, QString> > &baseInfo, const QLi
if(!archs.isEmpty()) {
m_architectures.swap(archs);
}
// consider general information as complete
m_hasGeneralInfo = m_hasAllGeneralInfo = true;
}
void Package::putSourceFile(const QString &path, const QByteArray &data)

View File

@ -108,6 +108,7 @@ public:
Repository *repository() const;
ChronoUtilities::DateTime timeStamp() const;
bool hasGeneralInfo() const;
bool hasAllGeneralInfo() const;
const QString &name() const;
const QString &version() const;
const QString &description() const;
@ -189,6 +190,7 @@ protected:
// general package meta data
bool m_hasGeneralInfo;
bool m_hasAllGeneralInfo;
QString m_name;
QString m_version;
QString m_description;
@ -274,6 +276,14 @@ inline bool Package::hasGeneralInfo() const
return m_hasGeneralInfo;
}
/*!
* \brief Returns whether all general information is available for the package.
*/
inline bool Package::hasAllGeneralInfo() const
{
return m_hasAllGeneralInfo;
}
/*!
* \brief Returns the name.
*/

View File

@ -1,10 +1,52 @@
#include "packagefinder.h"
#include "./packagefinder.h"
#include "./manager.h"
#include "../network/userrepository.h"
#include <cassert>
namespace RepoIndex {
PackageFinder::PackageFinder(QObject *parent) : QObject(parent)
PackageFinder::PackageFinder(Manager &manager, const QList<Dependency> &dependencies, QObject *parent)
: QObject(parent),
m_remainingReplies(0)
{
QStringList toRequest;
for(const auto &dependency : dependencies) {
if(auto *pkg = manager.packageProviding(dependency)) {
m_results << pkg;
} else {
toRequest << dependency.name;
}
}
if(manager.userRepository()) {
QReadLocker locker(manager.userRepository()->lock());
auto *reply = manager.userRepository()->requestFullPackageInfo(toRequest);
if(reply) {
++m_remainingReplies;
connect(reply, &PackageReply::resultsAvailable, this, &PackageFinder::addResults);
}
}
}
void PackageFinder::addResults()
{
assert(m_remainingReplies);
// add results
auto *reply = static_cast<PackageReply *>(sender());
auto *repo = reply->repository();
{
QReadLocker locker(repo->lock());
for(const auto &pkgName : reply->requestedPackages()) {
if(auto *pkg = repo->packageByName(pkgName)) {
m_results << pkg;
}
}
}
// finished?
if(!--m_remainingReplies) {
emit resultsAvailable();
}
}
} // namespace RepoIndex

View File

@ -1,20 +1,44 @@
#ifndef REPOINDEX_PACKAGEFINDER_H
#define REPOINDEX_PACKAGEFINDER_H
#include "./package.h"
#include <QObject>
namespace RepoIndex {
class Manager;
class PackageFinder : public QObject
{
Q_OBJECT
public:
explicit PackageFinder(QObject *parent = 0);
explicit PackageFinder(Manager &manager, const QList<Dependency> &dependencies, QObject *parent = nullptr);
const QList<Package *> results() const;
bool areAllResultsAvailable() const;
signals:
void resultsAvailable();
public slots:
private slots:
void addResults();
private:
int m_remainingReplies;
QList<Package *> m_results;
};
inline const QList<Package *> PackageFinder::results() const
{
return m_results;
}
inline bool PackageFinder::areAllResultsAvailable() const
{
return !m_remainingReplies;
}
} // namespace RepoIndex
#endif // REPOINDEX_PACKAGEFINDER_H

View File

@ -70,7 +70,7 @@ void PackageInfoLookup::addResultsDirectly(const QStringList &packageNames, cons
}
bool avail = false;
try {
if(const auto *pkg = packages.at(packageName)) {
if(const auto &pkg = packages.at(packageName)) {
avail = true;
if(m_part & Manager::Basics) {
res.insert(QStringLiteral("basics"), pkg->basicInfo());
@ -98,10 +98,10 @@ void PackageInfoLookup::addResultsFromReply()
addResultsDirectly(reply->requestedPackages(), reply->repository());
} else {
// TODO: bunch error messages together
for(const auto &packageName : packageNames) {
for(const auto &packageName : reply->requestedPackages()) {
QJsonObject res;
res.insert(QStringLiteral("name"), packageName);
res.insert(QStringLiteral("repo"), repo->name());
res.insert(QStringLiteral("repo"), reply->repository()->name());
res.insert(QStringLiteral("error"), reply->error());
m_results << res;
}

View File

@ -9,6 +9,7 @@
#include <QtConcurrent>
#include <iostream>
#include <cassert>
using namespace std;
@ -17,10 +18,11 @@ namespace RepoIndex {
/*!
* \brief Constructs a new reply for a single network reply.
*/
Reply::Reply(QNetworkReply *networkReply)
Reply::Reply(QNetworkReply *networkReply) :
m_remainingReplies(1)
{
networkReply->setParent(this);
connect(networkReply, &QNetworkReply::finished, this, &Reply::processData);
connect(networkReply, &QNetworkReply::finished, this, &Reply::replyFinished);
m_networkReplies.reserve(1);
m_networkReplies << networkReply;
}
@ -29,11 +31,24 @@ Reply::Reply(QNetworkReply *networkReply)
* \brief Constructs a new reply for multiple network replies.
*/
Reply::Reply(const QList<QNetworkReply *> networkReplies) :
m_networkReplies(networkReplies)
m_networkReplies(networkReplies),
m_remainingReplies(networkReplies.size())
{
for(auto *networkReply : networkReplies) {
networkReply->setParent(this);
connect(networkReply, &QNetworkReply::finished, this, &Reply::processData);
connect(networkReply, &QNetworkReply::finished, this, &Reply::replyFinished);
}
}
/*!
* \brief Called when a network reply has finished.
*/
void Reply::replyFinished()
{
assert(m_remainingReplies);
processData(static_cast<QNetworkReply *>(sender()));
if(!--m_remainingReplies) {
emit resultsAvailable();
}
}

View File

@ -30,10 +30,14 @@ signals:
void resultsAvailable();
private slots:
virtual void processData() = 0;
void replyFinished();
private:
virtual void processData(QNetworkReply *reply) = 0;
protected:
QList<QNetworkReply *> m_networkReplies;
unsigned int m_remainingReplies;
QString m_error;
};
@ -49,6 +53,7 @@ public:
PackageReply(QNetworkReply *networkReply, const QStringList &requestedPackages, Repository *repo);
PackageReply(const QList<QNetworkReply *> &networkReplies, const QStringList &requestedPackages, Repository *repo);
const QStringList &requestedPackages() const;
Repository *repository();
const Repository *repository() const;
protected:
@ -73,6 +78,11 @@ inline const QStringList &PackageReply::requestedPackages() const
return m_requestedPackages;
}
inline Repository *PackageReply::repository()
{
return m_repo;
}
inline const Repository *PackageReply::repository() const
{
return m_repo;

View File

@ -26,6 +26,8 @@ public:
bool isDone() const;
bool isVisited() const;
bool isOnlyDependency() const;
bool isPackageRequested() const;
void setPackageRequested();
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);
@ -36,6 +38,7 @@ private:
bool m_done;
bool m_visited;
bool m_onlyDep;
bool m_pkgRequested;
};
inline TaskInfo::TaskInfo(QString name, bool onlyDependency, const QList<TaskInfo *> &deps) :
@ -43,7 +46,8 @@ inline TaskInfo::TaskInfo(QString name, bool onlyDependency, const QList<TaskInf
m_deps(deps),
m_done(false),
m_visited(false),
m_onlyDep(onlyDependency)
m_onlyDep(onlyDependency),
m_pkgRequested(false)
{}
inline const QString &TaskInfo::name() const
@ -81,6 +85,16 @@ inline bool TaskInfo::isOnlyDependency() const
return m_onlyDep;
}
inline bool TaskInfo::isPackageRequested() const
{
return m_pkgRequested;
}
inline void TaskInfo::setPackageRequested()
{
m_pkgRequested = true;
}
void TaskInfo::add(QList<TaskInfo *> &results)
{
if(!isDone()) {
@ -143,27 +157,38 @@ BuildOrderResolver::BuildOrderResolver(const Manager &manager) :
m_manager(manager)
{}
QStringList BuildOrderResolver::resolve(const StringVector &packages) const
QStringList BuildOrderResolver::resolve(const StringVector &packages)
{
cerr << shchar << "Getting package information ..." << endl;
QList<TaskInfo *> tasks;
tasks.reserve(packages.size());
m_tasks.clear();
m_tasks.reserve(packages.size() * 2);
m_dependenciesToBeRequested.clear();
try {
// add a task for each specified package
for(const auto &pkgName : packages) {
tasks << new TaskInfo(QString::fromLocal8Bit(pkgName.data()));
m_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(int i = 0, size = m_tasks.size(); i != size; ++i) {
addDeps(m_tasks.at(i));
}
//for(auto *task : m_tasks) {
// addDeps(task);
//}
for(auto *task : tasks) {
addDeps(tasks, task);
while(!m_dependenciesToBeRequested.isEmpty()) {
cerr << shchar << "Dependencies to be requested:";
for(const Dependency &dep : m_dependenciesToBeRequested) {
cerr << ' ' << dep.name.toStdString();
}
cerr << endl;
// TODO: do requests
m_dependenciesToBeRequested.clear();
}
if(m_manager.config().isVerbose()) {
cerr << shchar << "Relevant packages: ";
for(const auto *task : tasks) {
cerr << task->name().toLocal8Bit().data() << ' ';
cerr << shchar << "Relevant packages:";
for(const auto *task : m_tasks) {
cerr << ' ' << task->name().toLocal8Bit().data();
}
cerr << endl;
}
@ -171,7 +196,7 @@ QStringList BuildOrderResolver::resolve(const StringVector &packages) const
QList<TaskInfo *> results;
try {
results.reserve(packages.size());
TaskInfo::addAll(tasks, results);
TaskInfo::addAll(m_tasks, results);
QStringList names;
names.reserve(results.size());
for(const auto *res : results) {
@ -182,7 +207,7 @@ QStringList BuildOrderResolver::resolve(const StringVector &packages) const
throw runtime_error("Can't resolve build order; the package " + cyclic.name().toStdString() + " is a cyclic dependency.");
}
} catch(...) {
qDeleteAll(tasks);
qDeleteAll(m_tasks);
throw;
}
}
@ -196,11 +221,18 @@ void BuildOrderResolver::printResults(const QStringList &results)
}
}
void BuildOrderResolver::addDeps(QList<TaskInfo *> &tasks, TaskInfo *task) const
/*!
* \brief Finds the package for the specified \a task and then adds dependencies.
*/
void BuildOrderResolver::addDeps(TaskInfo *task)
{
if(const auto pkg = m_manager.packageProviding(Dependency(task->name(), QString()))) {
Dependency dep(task->name(), QString());
if(const auto pkg = m_manager.packageProviding(dep)) {
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());
addDeps(task, pkg->dependencies());
} else if(!task->isPackageRequested()) {
task->setPackageRequested();
m_dependenciesToBeRequested << dep;
} 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";
@ -208,23 +240,29 @@ void BuildOrderResolver::addDeps(QList<TaskInfo *> &tasks, TaskInfo *task) const
}
}
void BuildOrderResolver::addDeps(QList<TaskInfo *> &tasks, TaskInfo *task, const QList<Dependency> &dependencies) const
/*!
* \brief Finds packages for the the specified \a dependencies and adds them to the specified \a task.
*/
void BuildOrderResolver::addDeps(TaskInfo *task, const QList<Dependency> &dependencies)
{
for(auto &dep : dependencies) {
if(const auto depPkg = m_manager.packageProviding(dep)) {
auto *depTask = TaskInfo::find(tasks, depPkg->name());
auto *depTask = TaskInfo::find(m_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));
m_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());
addDeps(depTask, depPkg->dependencies());
}
} else if(!task->isPackageRequested()) {
task->setPackageRequested();
m_dependenciesToBeRequested << dep;
} 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";

View File

@ -1,6 +1,8 @@
#ifndef PACKAGEMANAGEMENT_RESOLVEBUILDORDER_H
#define PACKAGEMANAGEMENT_RESOLVEBUILDORDER_H
#include "./packagefinder.h"
#include <c++utilities/application/argumentparser.h>
#include <QString>
@ -17,13 +19,17 @@ class BuildOrderResolver
public:
BuildOrderResolver(const Manager &manager);
QStringList resolve(const ApplicationUtilities::StringVector &packages) const;
QStringList resolve(const ApplicationUtilities::StringVector &packages);
static void printResults(const QStringList &results);
private:
void addDeps(QList<TaskInfo *> &tasks, TaskInfo *task) const;
void addDeps(QList<TaskInfo *> &tasks, TaskInfo *task, const QList<Dependency> &dependencies) const;
void addDeps(TaskInfo *task);
void addDeps(TaskInfo *task, const QList<Dependency> &dependencies);
const Manager &m_manager;
QList<TaskInfo *> m_tasks;
QList<Dependency> m_dependenciesToBeRequested;
//PackageFinder m_finder;
};
} // namespace PackageManagement

View File

@ -44,9 +44,8 @@ AurPackageReply::AurPackageReply(QNetworkReply *networkReply, const QStringList
m_userRepo(userRepo)
{}
void AurPackageReply::processData()
void AurPackageReply::processData(QNetworkReply *reply)
{
auto *reply = m_networkReplies.front();
if(reply->error() == QNetworkReply::NoError) {
QJsonParseError error;
const auto doc = QJsonDocument::fromJson(reply->readAll(), &error);
@ -71,7 +70,6 @@ void AurPackageReply::processData()
} else {
m_error = QStringLiteral("Unable to request data from AUR via AurJson: ") + reply->errorString();
}
emit resultsAvailable();
}
AurFullPackageReply::AurFullPackageReply(const QList<QNetworkReply *> &networkReplies, const QStringList &requestedPackages, UserRepository *userRepo) :
@ -79,9 +77,8 @@ AurFullPackageReply::AurFullPackageReply(const QList<QNetworkReply *> &networkRe
m_userRepo(userRepo)
{}
void AurFullPackageReply::processData()
void AurFullPackageReply::processData(QNetworkReply *reply)
{
auto *reply = static_cast<QNetworkReply *>(sender());
if(reply->error() == QNetworkReply::NoError) {
//QBuffer buffer;
//buffer.setData(reply->readAll());
@ -139,16 +136,14 @@ void AurFullPackageReply::processData()
if(!m_error.isEmpty()) {
qDebug() << m_error;
}
emit resultsAvailable();
}
AurSuggestionsReply::AurSuggestionsReply(QNetworkReply *networkReply, const QString &term, UserRepository *repo) :
SuggestionsReply(networkReply, term, repo)
{}
void AurSuggestionsReply::processData()
void AurSuggestionsReply::processData(QNetworkReply *reply)
{
auto *reply = m_networkReplies.front();
if(reply->error() == QNetworkReply::NoError) {
QJsonParseError error;
//QByteArray data = m_networkReply->readAll();
@ -188,7 +183,6 @@ void AurSuggestionsReply::processData()
} else {
m_error = QStringLiteral("Unable to request data from AUR: ") + reply->errorString();
}
emit resultsAvailable();
}
UserRepository::UserRepository(QNetworkAccessManager &networkAccessManager, QObject *parent) :
@ -222,13 +216,14 @@ AurSuggestionsReply *UserRepository::requestSuggestions(const QString &term)
size_t remainingSuggestions = 20;
//for(auto i = packages().lower_bound(term), end = packages().cend(); i != end && remainingSuggestions && i->first.startsWith(term, Qt::CaseInsensitive); ++i, --remainingSuggestions);
for(const auto &pkgEntry : packages()) {
if(pkgEntry.first.compare(term, Qt::CaseInsensitive) == 0) {
if(pkgEntry.first.contains(term, Qt::CaseInsensitive)) {
if(!(--remainingSuggestions)) {
break;
}
}
}
if(remainingSuggestions) {
if(remainingSuggestions && !m_requestedSuggestions.contains(term)) {
m_requestedSuggestions << term;
auto url = m_aurRpcUrl;
QUrlQuery query;
query.addQueryItem(rpcRequestTypeKey, term.size() < 3 ? rpcRequestTypeSuggest : rpcRequestTypeSearch);
@ -269,7 +264,7 @@ AurFullPackageReply *UserRepository::requestFullPackageInfo(const QStringList &p
for(const auto &packageName : packageNames) {
try {
const auto &pkg = m_packages.at(packageName);
if(!pkg->hasGeneralInfo() || !pkg->hasSourceRelatedMetaData() || forceUpdate) {
if(!pkg->hasAllGeneralInfo() || !pkg->hasSourceRelatedMetaData() || forceUpdate) {
if(pkg->tarUrl().isEmpty()) {
replies << m_networkAccessManager.get(QNetworkRequest(m_aurSnapshotPath.arg(pkg->name())));
} else {

View File

@ -24,7 +24,7 @@ public:
AurPackageReply(QNetworkReply *networkReply, const QStringList &requestedPackages, UserRepository *userRepo);
private slots:
void processData();
void processData(QNetworkReply *reply);
private:
UserRepository *m_userRepo;
@ -37,7 +37,7 @@ public:
AurFullPackageReply(const QList<QNetworkReply *> &networkReplies, const QStringList &requestedPackages, UserRepository *userRepo);
private slots:
void processData();
void processData(QNetworkReply *reply);
private:
UserRepository *m_userRepo;
@ -50,7 +50,7 @@ public:
AurSuggestionsReply(QNetworkReply *networkReply, const QString &term, UserRepository *repo);
private slots:
void processData();
void processData(QNetworkReply *reply);
};
class UserRepository : public Repository
@ -74,6 +74,7 @@ protected:
private:
QNetworkAccessManager &m_networkAccessManager;
QSet<QString> m_requestedSuggestions;
static QString m_aurBaseUrl;
static QUrl m_aurRpcUrl;
static QUrl m_aurPkgbuildUrl;

View File

@ -27,8 +27,16 @@
"server": [
"https://localhost/repo/arch/$repo/os/$arch"
]
},
{"name": "ownstuff-testing",
"sourcesDir": "path/to/local/source/dir",
"packagesDir": "/run/media/devel/repo/arch/ownstuff-testing/os/x86_64",
"upgradeSources": ["aur"],
"server": [
"https://localhost/repo/arch/$repo/os/$arch"
]
}
]
]
}
}

View File

@ -407,7 +407,7 @@
var entryExists = false;
for(var i = 0, len = pkgMgr.entries.length; i < len; ++i) {
var pkgEntry = pkgMgr.entries[i];
if(pkgEntry.name === packageName && pkgEntry.repoName === repoName) {
if(pkgEntry.name === packageName && pkgEntry.repoEntry.name === repoName) {
entryExists = true;
break;
}

View File

@ -67,12 +67,12 @@
// if there is no page because there are no package entries, pageElement is null
if(pageElement) {
// show elements of selected page
var packageSelection = {}; // package selection for requesting package infos
var packageSelection = {}; // package selection for requesting package info
var entriesRequired = false;
pageElement.forRange(function(i) {
var entry = mgr.filteredEntries[i];
entry.add(mgr.entryContainer);
if(!entry.info.basic) {
if(!entry.info.basics) {
var repoArray = packageSelection[entry.info.repo];
if(!Array.isArray(repoArray)) {
packageSelection[entry.info.repo] = [{index: entry.info.index, name: entry.info.name}];

View File

@ -126,6 +126,7 @@
pagination.internalPageSelected(this);
};
// invokes the specified function for each index of the currently visible range
pageElement.forRange = function(func, maxIndex) {
for(var i = this.pageIndex * this.pagination.entriesPerPage, pagesLeft = this.pagination.entriesPerPage;
pagesLeft > 0 && i < maxIndex; ++i, --pagesLeft) {

View File

@ -146,7 +146,7 @@
// show elements of selected page
pageElement.forRange(function(i) {
var entry = mgr.filteredEntries[i];
entry.add(mgr.entryContainer);
entry.add(mgr.entryContainer); // adds entry to the entry container
}, mgr.filteredEntries.length);
}
};