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; }
/** * 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); }