PackageVersion *AbstractRepository::findBestMatchToInstall(
        const Dependency &dep, const QList<PackageVersion *> &avoid,
        QString *err)
{
    PackageVersion* res = 0;

    QList<PackageVersion*> pvs = getPackageVersions_(dep.package, err);
    if (err->isEmpty()) {
        for (int i = 0; i < pvs.count(); i++) {
            PackageVersion* pv = pvs.at(i);
            if (dep.test(pv->version) &&
                    pv->download.isValid() &&
                    PackageVersion::indexOf(avoid, pv) < 0) {
                if (res == 0 || pv->version.compare(res->version) > 0)
                    res = pv;
            }
        }
    }

    if (res) {
        res = res->clone();
    }
    qDeleteAll(pvs);

    return res;
}
bool AbstractRepository::includesRemoveItself(
        const QList<InstallOperation *> &install_)
{
    bool res = false;

    QString exeDir = WPMUtils::getExeDir();
    for (int i = 0; i < install_.count(); i++) {
        InstallOperation* op = install_.at(i);
        if (!op->install) {
            QString err;
            PackageVersion* pv = this->findPackageVersion_(
                    op->package, op->version, &err);
            if (err.isEmpty() && pv) {
                QString path = pv->getPath();
                delete pv;

                if (WPMUtils::pathEquals(exeDir, path) ||
                        WPMUtils::isUnder(exeDir, path)) {
                    res = true;
                    break;
                }
            }
        }
    }

    return res;
}
示例#3
0
/**
 * Create a PackageVersion object and add it to the tree. If a version
 * with same version string already exists, it is replaced.
 * No version is created if the version string is empty.
 *
 * @param versionString  The version string, e.g. "2.6.11-r6".
 * @return  A pointer to the new PackageVersion object.
 *          NULL if the version string was empty and the object
 *          has not been created.
 */
PackageVersion* Package::insertVersion( const QString& versionString )
{
	if( versionString.isEmpty() )
		return NULL;

	PackageVersion* version = createPackageVersion( versionString );
	PackageVersionMap::iterator versionIterator =
		m_versions.insert( version->version(), version );

	if( versionIterator == m_versions.end() )
		return NULL; // could not be inserted into m_versions
	else
		return *versionIterator;
}
QList<PackageVersion *> AbstractRepository::findAllMatchesToInstall(
        const Dependency &dep, const QList<PackageVersion *> &avoid,
        QString *err)
{
    QList<PackageVersion*> res;

    QList<PackageVersion*> pvs = getPackageVersions_(dep.package, err);
    if (err->isEmpty()) {
        for (int i = 0; i < pvs.count(); i++) {
            PackageVersion* pv = pvs.at(i);
            if (dep.test(pv->version) &&
                    pv->download.isValid() &&
                    PackageVersion::indexOf(avoid, pv) < 0) {
                res.append(pv->clone());
            }
        }
    }
    qDeleteAll(pvs);

    return res;
}
PackageVersion* AbstractRepository::findNewestInstallablePackageVersion_(
        const QString &package, QString* err) const
{
    PackageVersion* r = 0;

    QList<PackageVersion*> pvs = this->getPackageVersions_(package, err);
    if (err->isEmpty()) {
        for (int i = 0; i < pvs.count(); i++) {
            PackageVersion* p = pvs.at(i);
            if (r == 0 || p->version.compare(r->version) > 0) {
                if (p->download.isValid())
                    r = p;
            }
        }
    }

    if (r)
        r = r->clone();

    qDeleteAll(pvs);

    return r;
}
void ScanDiskThirdPartyPM::scan(const QString& path, Job* job, int level,
        QStringList& ignore) const
{
    if (ignore.contains(path))
        return;

    QDir aDir(path);

    QMap<QString, QString> path2sha1;

    DBRepository* r = DBRepository::getDefault();
    QString err;
    QList<PackageVersion*> packageVersions =
            r->getPackageVersionsWithDetectFiles(&err);

    // qDebug() << "package versions with detect files: " << packageVersions.count();

    if (!err.isEmpty())
        job->setErrorMessage(err);

    for (int i = 0; i < packageVersions.count(); i++) {
        if (!job->shouldProceed())
            break;

        PackageVersion* pv = packageVersions.at(i);
        if (!pv->installed() && pv->detectFiles.count() > 0) {
            boolean ok = true;
            for (int j = 0; j < pv->detectFiles.count(); j++) {
                bool fileOK = false;
                DetectFile* df = pv->detectFiles.at(j);
                if (aDir.exists(df->path)) {
                    QString fullPath = path + "\\" + df->path;
                    QFileInfo f(fullPath);
                    if (f.isFile() && f.isReadable()) {
                        QString sha1 = path2sha1.value(df->path);
                        if (sha1.isEmpty()) {
                            sha1 = WPMUtils::sha1(fullPath);
                            path2sha1[df->path] = sha1;
                        }
                        if (df->sha1 == sha1) {
                            fileOK = true;
                        }
                    }
                }
                if (!fileOK) {
                    ok = false;
                    break;
                }
            }

            if (ok) {
                pv->setPath(path);
                return;
            }
        }
    }

    if (job && !job->isCancelled()) {
        QFileInfoList entries = aDir.entryInfoList(
                QDir::NoDotAndDotDot | QDir::Dirs);
        int count = entries.size();
        for (int idx = 0; idx < count; idx++) {
            if (job && job->isCancelled())
                break;

            QFileInfo entryInfo = entries[idx];
            QString name = entryInfo.fileName();

            if (job) {
                job->setTitle(name);
                if (job->isCancelled())
                    break;
            }

            Job* djob;
            if (level < 2)
                djob = job->newSubJob(1.0 / count);
            else
                djob = 0;
            scan(path + "\\" + name.toLower(), djob, level + 1, ignore);

            if (job) {
                job->setProgress(((double) idx) / count);
            }
        }
    }

    qDeleteAll(packageVersions);

    if (job)
        job->complete();
}
QString AbstractRepository::planUpdates(const QList<Package*> packages,
        QList<Dependency*> ranges,
        QList<InstallOperation*>& ops, bool keepDirectories,
        bool install, const QString &where_)
{
    QString err;

    QList<PackageVersion*> installed = getInstalled_(&err);
    QList<PackageVersion*> newest, newesti;
    QList<bool> used;

    // packages first
    if (err.isEmpty()) {
        for (int i = 0; i < packages.count(); i++) {
            Package* p = packages.at(i);

            PackageVersion* a = findNewestInstallablePackageVersion_(p->name,
                    &err);
            if (!err.isEmpty())
                break;

            if (a == 0) {
                err = QString(QObject::tr("No installable version found for the package %1")).
                        arg(p->title);
                break;
            }

            PackageVersion* b = findNewestInstalledPackageVersion_(p->name, &err);
            if (!err.isEmpty()) {
                err = QString(QObject::tr("Cannot find the newest installed version for %1: %2")).
                        arg(p->title).arg(err);
                break;
            }

            if (b == 0) {
                if (!install) {
                    err = QString(QObject::tr("No installed version found for the package %1")).
                            arg(p->title);
                    break;
                }
            }

            if (b == 0 || a->version.compare(b->version) > 0) {
                newest.append(a);
                newesti.append(b);
                used.append(false);
            }
        }
    }

    // version ranges second
    if (err.isEmpty()) {
        for (int i = 0; i < ranges.count(); i++) {
            Dependency* d = ranges.at(i);
            QScopedPointer<Package> p(findPackage_(d->package));
            if (!p.data()) {
                err = QString(QObject::tr("Cannot find the package %1")).
                        arg(d->package);
                break;
            }

            PackageVersion* a = findBestMatchToInstall(*d,
                    QList<PackageVersion*>(), &err);
            if (!err.isEmpty())
                break;

            if (a == 0) {
                err = QString(QObject::tr("No installable version found for the package %1")).
                        arg(p->title);
                break;
            }

            InstalledPackageVersion* ipv = findHighestInstalledMatch(*d);
            PackageVersion* b = 0;
            if (ipv) {
                b = findPackageVersion_(ipv->package, ipv->version, &err);
                if (!err.isEmpty()) {
                    err = QString(QObject::tr("Cannot find the newest installed version for %1: %2")).
                            arg(p->title).arg(err);
                    break;
                }
            }

            if (b == 0) {
                if (!install) {
                    err = QString(QObject::tr("No installed version found for the package %1")).
                            arg(p->title);
                    break;
                }
            }

            if (b == 0 || a->version.compare(b->version) > 0) {
                newest.append(a);
                newesti.append(b);
                used.append(false);
            }
        }
    }

    if (err.isEmpty()) {
        // many packages cannot be installed side-by-side and overwrite for
        // example
        // the shortcuts of the old version in the start menu. We try to find
        // those packages where the old version can be uninstalled first and
        // then
        // the new version installed. This is the reversed order for an update.
        // If this is possible and does not affect other packages, we do this
        // first.
        for (int i = 0; i < newest.count(); i++) {
            QList<PackageVersion*> avoid;
            QList<InstallOperation*> ops2;
            QList<PackageVersion*> installedCopy = installed;

            PackageVersion* b = newesti.at(i);
            if (b) {
                QString err = b->planUninstallation(
                        installedCopy, ops2);
                if (err.isEmpty()) {
                    QString where;
                    if (i == 0 && !where_.isEmpty())
                        where = where_;
                    else if (keepDirectories)
                        where = b->getPath();

                    err = newest.at(i)->planInstallation(installedCopy, ops2,
                            avoid, where);
                    if (err.isEmpty()) {
                        if (ops2.count() == 2) {
                            used[i] = true;
                            installed = installedCopy;
                            ops.append(ops2[0]);
                            ops.append(ops2[1]);
                            ops2.clear();
                        }
                    }
                }
            }

            qDeleteAll(ops2);
        }
    }

    if (err.isEmpty()) {
        for (int i = 0; i < newest.count(); i++) {
            if (!used[i]) {
                QString where;
                PackageVersion* b = newesti.at(i);
                if (keepDirectories && b)
                    where = b->getPath();

                QList<PackageVersion*> avoid;
                err = newest.at(i)->planInstallation(installed, ops, avoid,
                        where);
                if (!err.isEmpty())
                    break;
            }
        }
    }

    if (err.isEmpty()) {
        for (int i = 0; i < newesti.count(); i++) {
            if (!used[i]) {
                PackageVersion* b = newesti.at(i);
                if (b) {
                    err = b->planUninstallation(installed, ops);
                    if (!err.isEmpty())
                        break;
                }
            }
        }
    }

    if (err.isEmpty()) {
        InstallOperation::simplify(ops);
    }

    qDeleteAll(installed);
    qDeleteAll(newest);
    qDeleteAll(newesti);

    return err;
}
void AbstractRepository::process(Job *job,
        const QList<InstallOperation *> &install_, DWORD programCloseType,
        bool printScriptOutput, bool interactive)
{
    QDir d;

    QList<InstallOperation *> install = install_;

    // reoder the operations if a package is updated. In this case it is better
    // to uninstall the old first and then install the new one.
    if (install.size() == 2) {
        InstallOperation* first = install.at(0);
        InstallOperation* second = install.at(1);
        if (first->package == second->package &&
                first->install && !second->install) {
            install.insert(0, second);
            install.removeAt(2);
        }
    }

    // search for PackageVersion objects
    QList<PackageVersion*> pvs;
    for (int i = 0; i < install.size(); i++) {
        InstallOperation* op = install.at(i);

        QString err;
        PackageVersion* pv = op->findPackageVersion(&err);
        if (!err.isEmpty()) {
            job->setErrorMessage(QString(
                    QObject::tr("Cannot find the package version %1 %2: %3")).
                    arg(op->package).
                    arg(op->version.getVersionString()).
                    arg(err));
            break;
        }
        if (!pv) {
            job->setErrorMessage(QString(
                    QObject::tr("Cannot find the package version %1 %2")).
                    arg(op->package).
                    arg(op->version.getVersionString()));
            break;
        }
        pvs.append(pv);
    }

    if (job->shouldProceed()) {
        for (int j = 0; j < pvs.size(); j++) {
            PackageVersion* pv = pvs.at(j);
            pv->lock();
        }
    }

    int n = install.count();

    // where the binary was downloaded
    QStringList dirs;

    // names of the binaries relative to the directory
    QStringList binaries;

    // 70% for downloading the binaries
    if (job->shouldProceed()) {
        // downloading packages
        for (int i = 0; i < install.count(); i++) {
            InstallOperation* op = install.at(i);
            PackageVersion* pv = pvs.at(i);
            if (op->install) {
                QString txt = QObject::tr("Downloading %1").arg(
                        pv->toString());

                Job* sub = job->newSubJob(0.7 / n, txt, true, true);

                // dir is not the final installation directory. It can be
                // changed later during the installation.
                QString dir = op->where;
                if (dir.isEmpty()) {
                    dir = pv->getIdealInstallationDirectory();
                }
                dir = WPMUtils::findNonExistingFile(dir, "");

                if (d.exists(dir)) {
                    sub->setErrorMessage(
                            QObject::tr("Directory %1 already exists").
                            arg(dir));
                    dirs.append("");
                    binaries.append("");
                } else {
                    dirs.append(dir);

                    QString binary = pv->download_(sub, dir, interactive);
                    binaries.append(QFileInfo(binary).fileName());
                }
            } else {
                dirs.append("");
                binaries.append("");
                job->setProgress(job->getProgress() + 0.7 / n);
            }

            if (!job->shouldProceed())
                break;
        }
    }

    // 10% for stopping the packages
    if (job->shouldProceed()) {
        for (int i = 0; i < install.count(); i++) {
            InstallOperation* op = install.at(i);
            PackageVersion* pv = pvs.at(i);
            if (!op->install) {
                Job* sub = job->newSubJob(0.1 / n,
                        QObject::tr("Stopping the package %1 of %2").
                        arg(i + 1).arg(n));
                pv->stop(sub, programCloseType, printScriptOutput);
                if (!sub->getErrorMessage().isEmpty()) {
                    job->setErrorMessage(sub->getErrorMessage());
                    break;
                }
            } else {
                job->setProgress(job->getProgress() + 0.1 / n);
            }
        }
    }

    int processed = 0;

    // 19% for removing/installing the packages
    if (job->shouldProceed()) {
        // installing/removing packages
        for (int i = 0; i < install.count(); i++) {
            InstallOperation* op = install.at(i);
            PackageVersion* pv = pvs.at(i);
            QString txt;
            if (op->install)
                txt = QString(QObject::tr("Installing %1")).arg(
                        pv->toString());
            else
                txt = QString(QObject::tr("Uninstalling %1")).arg(
                        pv->toString());

            Job* sub = job->newSubJob(0.19 / n, txt, true, true);
            if (op->install) {
                QString dir = dirs.at(i);
                QString binary = binaries.at(i);

                if (op->where.isEmpty()) {
                    // if we are not forced to install in a particular
                    // directory, we try to use the ideal location
                    QString try_ = pv->getIdealInstallationDirectory();
                    if (WPMUtils::pathEquals(try_, dir) ||
                            (!d.exists(try_) && d.rename(dir, try_))) {
                        dir = try_;
                    } else {
                        try_ = pv->getSecondaryInstallationDirectory();
                        if (WPMUtils::pathEquals(try_, dir) ||
                                (!d.exists(try_) && d.rename(dir, try_))) {
                            dir = try_;
                        } else {
                            try_ = WPMUtils::findNonExistingFile(try_, "");
                            if (WPMUtils::pathEquals(try_, dir) ||
                                    (!d.exists(try_) && d.rename(dir, try_))) {
                                dir = try_;
                            }
                        }
                    }
                } else {
                    if (d.exists(op->where)) {
                        if (!WPMUtils::pathEquals(op->where, dir)) {
                            // we should install in a particular directory, but it
                            // exists.
                            Job* djob = sub->newSubJob(1,
                                    QObject::tr("Deleting temporary directory %1").
                                    arg(dir));
                            QDir ddir(dir);
                            WPMUtils::removeDirectory(djob, ddir);
                            job->setErrorMessage(QObject::tr(
                                    "Cannot install %1 into %2. The directory already exists.").
                                    arg(pv->toString(true)).arg(op->where));
                            break;
                        }
                    } else {
                        if (d.rename(dir, op->where))
                            dir = op->where;
                        else {
                            // we should install in a particular directory, but it
                            // exists.
                            Job* djob = sub->newSubJob(1,
                                    QObject::tr("Deleting temporary directory %1").
                                    arg(dir));
                            QDir ddir(dir);
                            WPMUtils::removeDirectory(djob, ddir);
                            job->setErrorMessage(QObject::tr(
                                    "Cannot install %1 into %2. Cannot rename %3.").
                                    arg(pv->toString(true), op->where, dir));
                            break;
                        }
                    }
                }

                pv->install(sub, dir, binary, printScriptOutput,
                        programCloseType);
            } else
                pv->uninstall(sub, printScriptOutput, programCloseType);

            if (!job->shouldProceed())
                break;

            processed = i + 1;
        }
    }

    // removing the binaries if we should not proceed
    if (!job->shouldProceed()) {
        for (int i = processed; i < dirs.count(); i++) {
            QString dir = dirs.at(i);
            if (!dir.isEmpty()) {
                QString txt = QObject::tr("Deleting %1").arg(dir);

                Job* sub = job->newSubJob(0.01 / dirs.count(), txt, true, false);
                QDir ddir(dir);
                WPMUtils::removeDirectory(sub, ddir);
            } else {
                job->setProgress(job->getProgress() + 0.01 / dirs.count());
            }
        }
    }

    for (int j = 0; j < pvs.size(); j++) {
        PackageVersion* pv = pvs.at(j);
        pv->unlock();
    }

    qDeleteAll(pvs);

    if (job->shouldProceed())
        job->setProgress(1);

    job->complete();
}
void SettingsFrame::on_buttonBox_clicked(QAbstractButton *button)
{
    MainWindow* mw = MainWindow::getInstance();

    if (mw->hardDriveScanRunning) {
        mw->addErrorMessage(QObject::tr("Cannot change settings now. The hard drive scan is running."));
        return;
    }

    QString err;
    PackageVersion* locked = PackageVersion::findLockedPackageVersion(&err);
    if (locked) {
        err = QObject::tr("Cannot find locked package versions: %1").
                arg(err);
        mw->addErrorMessage(err);
        delete locked;
        return;
    }

    if (locked) {
        QString msg(QObject::tr("Cannot change settings now. The package %1 is locked by a currently running installation/removal."));
        mw->addErrorMessage(msg.arg(locked->toString()));
        delete locked;
        return;
    }

    QStringList list = getRepositoryURLs();

    if (err.isEmpty() && list.count() == 0)
        err = QObject::tr("No repositories defined");

    if (err.isEmpty()) {
        err = WPMUtils::checkInstallationDirectory(getInstallationDirectory());
    }

    QList<QUrl*> urls;
    if (err.isEmpty()) {
        for (int i = 0; i < list.count(); i++) {
            QUrl* url = new QUrl(list.at(i));
            urls.append(url);
            if (!url->isValid()) {
                err = QString(QObject::tr("%1 is not a valid repository address")).arg(
                        list.at(i));
                break;
            }
        }
    }

    if (err.isEmpty()) {
        WPMUtils::setInstallationDirectory(getInstallationDirectory());
        WPMUtils::setCloseProcessType(getCloseProcessType());
    }

    bool repsChanged = false;

    if (err.isEmpty()) {
        QList<QUrl*> oldList = Repository::getRepositoryURLs(&err);
        repsChanged = oldList.count() != urls.count();
        if (!repsChanged) {
            for (int i = 0; i < oldList.count(); i++) {
                if ((*oldList.at(i)) != (*urls.at(i))) {
                    repsChanged = true;
                    break;
                }
            }
        }
        qDeleteAll(oldList);
        oldList.clear();
    }

    if (err.isEmpty()) {
        if (repsChanged) {
            if (mw->reloadRepositoriesThreadRunning) {
                err = QObject::tr("Cannot change settings now. The repositories download is running.");
            } else {
                Repository::setRepositoryURLs(urls, &err);
                if (err.isEmpty()) {
                    mw->closeDetailTabs();
                    mw->recognizeAndLoadRepositories(false);
                }
            }
        }
    }

    qDeleteAll(urls);
    urls.clear();

    if (err.isEmpty()) {
        WindowsRegistry m(HKEY_LOCAL_MACHINE, false, KEY_ALL_ACCESS);
        WindowsRegistry wr = m.createSubKey(
                "Software\\Npackd\\Npackd\\InstallationDirs", &err,
                KEY_ALL_ACCESS);

        QStringList dirs;
        for (int i = 0; i < this->ui->comboBoxDir->count(); i++)
            dirs.append(this->ui->comboBoxDir->itemText(i));
        if (err.isEmpty()) {
            wr.saveStringList(dirs);
        }

        // it is not important, whether the list of directories is saved or not
        err = "";
    }

    if (!err.isEmpty())
        mw->addErrorMessage(err, err, true, QMessageBox::Critical);
}