void PackageProcessor::HandleFile (int packageId, const QUrl& url, PackageProcessor::Mode mode) { QString path = Core::Instance () .GetExtResourceManager ()->GetResourcePath (url); QProcess *unarch = new QProcess (this); connect (unarch, SIGNAL (finished (int, QProcess::ExitStatus)), this, SLOT (handlePackageUnarchFinished (int, QProcess::ExitStatus))); connect (unarch, SIGNAL (error (QProcess::ProcessError)), this, SLOT (handleUnarchError (QProcess::ProcessError))); QString dirname = Util::GetTemporaryName ("lackman_stagingarea"); QStringList args; #ifdef Q_WS_WIN args << "x"; #else args << "xzf"; #endif args << path; #ifdef Q_WS_WIN args << "-o"; #else args << "-C"; #endif args << dirname; unarch->setProperty ("PackageID", packageId); unarch->setProperty ("StagingDirectory", dirname); unarch->setProperty ("Path", path); unarch->setProperty ("Mode", mode); QFileInfo sdInfo (dirname); QDir stagingParentDir (sdInfo.path ()); if (!stagingParentDir.exists (sdInfo.fileName ()) && !stagingParentDir.mkdir (sdInfo.fileName ())) { qWarning () << Q_FUNC_INFO << "unable to create staging directory" << sdInfo.fileName () << "in" << sdInfo.path (); QString errorString = tr ("Unable to create staging directory %1.") .arg (sdInfo.fileName ()); emit packageInstallError (packageId, errorString); return; } #ifdef Q_WS_WIN QString command = "7za"; #else QString command = "tar"; #endif unarch->start (command, args); }
void PackageProcessor::handleUnarchError (QProcess::ProcessError error) { sender ()->deleteLater (); QByteArray errString = qobject_cast<QProcess*> (sender ())->readAllStandardError (); qWarning () << Q_FUNC_INFO << "unable to unpack for" << sender ()->property ("PackageID").toInt () << sender ()->property ("Path").toString () << "with" << error << errString; QString errorString = tr ("Unable to unpack package archive, unpacker died with %1: %2.") .arg (error) .arg (QString::fromUtf8 (errString)); emit packageInstallError (sender ()->property ("PackageID").toInt (), errorString); CleanupDir (sender ()->property ("StagingDirectory").toString ()); }
bool PackageProcessor::CleanupBeforeUpdate (int oldId, int newId) { try { Remove (oldId); } catch (const std::exception& e) { qWarning () << Q_FUNC_INFO << "while removing package" << oldId << "for update to" << newId << "got exception:" << e.what (); const auto& str = tr ("Unable to update package: %1.") .arg (QString::fromUtf8 (e.what ())); emit packageInstallError (newId, str); return false; } return true; }
bool PackageProcessor::HandleEntry (int packageId, const QFileInfo& fi, const QString& stagingDir, QDir& packageDir) { QFile dbFile (DBDir_.filePath (QString::number (packageId))); if (!dbFile.open (QIODevice::WriteOnly | QIODevice::Append)) { qWarning () << Q_FUNC_INFO << "could not open DB file" << dbFile.fileName () << "for write:" << dbFile.errorString (); return false; } QString sourceName = fi.absoluteFilePath (); sourceName = sourceName.mid (stagingDir.length ()); if (sourceName.at (0) == '/') sourceName = sourceName.mid (1); if (fi.isFile ()) { QString destName = packageDir.filePath (sourceName); #ifndef QT_NO_DEBUG qDebug () << Q_FUNC_INFO << "gotta copy" << fi.absoluteFilePath () << "to" << destName; #endif QFile file (fi.absoluteFilePath ()); if (!file.copy (destName)) { qWarning () << Q_FUNC_INFO << "could not copy" << fi.absoluteFilePath () << "to" << destName << "because of" << file.errorString (); QString errorString = tr ("Could not copy file %1 because of %2.") .arg (sourceName) .arg (file.errorString ()); emit packageInstallError (packageId, errorString); return false; } } else if (fi.isDir ()) { #ifndef QT_NO_DEBUG qDebug () << Q_FUNC_INFO << "gotta create" << sourceName << "for" << fi.absoluteFilePath (); #endif if (!packageDir.mkpath (sourceName)) { qWarning () << Q_FUNC_INFO << "unable to mkdir" << sourceName << "in" << packageDir.path (); QString errorString = tr ("Unable to create directory %1.") .arg (sourceName); emit packageInstallError (packageId, errorString); return false; } } dbFile.write (sourceName.toUtf8 ()); dbFile.write ("\n"); return true; }
void PackageProcessor::HandleFile (int packageId, const QUrl& url, PackageProcessor::Mode mode) { QString path = Core::Instance ().GetExtResourceManager ()->GetResourcePath (url); PackageShortInfo info; try { info = Core::Instance ().GetStorage ()->GetPackage (packageId); } catch (const std::exception& e) { qWarning () << Q_FUNC_INFO << "unable to get package info for" << packageId << e.what (); return; } const QString& archiver = info.VersionArchivers_ .value (info.Versions_.value (0), "gz"); QProcess *unarch = new QProcess (this); connect (unarch, SIGNAL (finished (int, QProcess::ExitStatus)), this, SLOT (handlePackageUnarchFinished (int, QProcess::ExitStatus))); connect (unarch, SIGNAL (error (QProcess::ProcessError)), this, SLOT (handleUnarchError (QProcess::ProcessError))); QString dirname = Util::GetTemporaryName ("lackman_stagingarea"); QStringList args; #ifdef Q_OS_WIN32 args << "x" << "-ttar" << "-y" << "-si"; QString outDirArg ("-o"); outDirArg.append (dirname); args << outDirArg; QProcess *firstStep = new QProcess (unarch); firstStep->setStandardOutputProcess (unarch); QStringList firstStepArgs; firstStepArgs << "x" << "-y" << "-so" << path; #else if (archiver == "lzma") args << "--lzma"; args << "-xf"; args << path; args << "-C"; args << dirname; #endif unarch->setProperty ("PackageID", packageId); unarch->setProperty ("StagingDirectory", dirname); unarch->setProperty ("Path", path); unarch->setProperty ("Mode", mode); QFileInfo sdInfo (dirname); QDir stagingParentDir (sdInfo.path ()); if (!stagingParentDir.exists (sdInfo.fileName ()) && !stagingParentDir.mkdir (sdInfo.fileName ())) { qWarning () << Q_FUNC_INFO << "unable to create staging directory" << sdInfo.fileName () << "in" << sdInfo.path (); QString errorString = tr ("Unable to create staging directory %1.") .arg (sdInfo.fileName ()); emit packageInstallError (packageId, errorString); return; } #ifdef Q_OS_WIN32 QString command = "7za"; firstStep->start (command, firstStepArgs); #else QString command = "tar"; #endif unarch->start (command, args); }
void PackageProcessor::handlePackageUnarchFinished (int ret, QProcess::ExitStatus) { sender ()->deleteLater (); QProcess *unarch = qobject_cast<QProcess*> (sender ()); int packageId = unarch->property ("PackageID").toInt (); const auto& stagingDir = unarch->property ("StagingDirectory").toString (); Mode mode = static_cast<Mode> (unarch->property ("Mode").toInt ()); auto cleanupGuard = std::shared_ptr<void> (nullptr, [&stagingDir, this] (void*) { CleanupDir (stagingDir); }); if (ret) { QString errString = QString::fromUtf8 (unarch->readAllStandardError ()); qWarning () << Q_FUNC_INFO << "unpacker exited with" << ret << errString << "for" << packageId << unarch->property ("Path").toString (); QString errorString = tr ("Unable to unpack package archive, unpacker exited with %1: %2.") .arg (ret) .arg (errString); emit packageInstallError (packageId, errorString); return; } int oldId = -1; if (mode == MUpdate) { oldId = Core::Instance ().GetStorage ()->FindInstalledPackage (packageId); if (!CleanupBeforeUpdate (oldId, packageId)) { qWarning () << Q_FUNC_INFO << "unable to cleanup"; return; } } QDir packageDir; try { packageDir = Core::Instance ().GetPackageDir (packageId); } catch (const std::exception& e) { qWarning () << Q_FUNC_INFO << "while trying to get dir for package" << packageId << "got we exception" << e.what (); QString errorString = tr ("Unable to get directory for the package: %1.") .arg (QString::fromUtf8 (e.what ())); emit packageInstallError (packageId, errorString); return; } QDirIterator dirIt (stagingDir, QDir::NoDotAndDotDot | QDir::Readable | QDir::NoSymLinks | QDir::Dirs | QDir::Files, QDirIterator::Subdirectories); while (dirIt.hasNext ()) { dirIt.next (); QFileInfo fi = dirIt.fileInfo (); if (fi.isDir () || fi.isFile ()) if (!HandleEntry (packageId, fi, stagingDir, packageDir)) { try { Remove (packageId); } catch (const std::exception& e) { qWarning () << Q_FUNC_INFO << "while removing partially installed package" << packageId << "got:" << e.what (); } QString errorString = tr ("Unable to copy " "files from staging area to " "destination directory."); emit packageInstallError (packageId, errorString); return; } } switch (mode) { case MInstall: emit packageInstalled (packageId); break; case MUpdate: emit packageUpdated (oldId, packageId); break; } }