UpdateManager.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. #include "QsLog.h"
  2. #include <QDir>
  3. #include <QStandardPaths>
  4. #include <QCoreApplication>
  5. #include <QProcess>
  6. #include "UpdateManager.h"
  7. #include "utils/Utils.h"
  8. #include "utils/HelperLauncher.h"
  9. #include "system/SystemComponent.h"
  10. #ifdef KONVERGO_OPENELEC
  11. #include "OEUpdateManager.h"
  12. #endif
  13. #ifdef Q_OS_WIN
  14. #include "UpdateManagerWin32.h"
  15. #endif
  16. UpdateManager* g_updateManager;
  17. ///////////////////////////////////////////////////////////////////////////////////////////////////
  18. UpdateManager* UpdateManager::Get()
  19. {
  20. if (!g_updateManager)
  21. {
  22. #if defined(KONVERGO_OPENELEC)
  23. g_updateManager = new OEUpdateManager(nullptr);
  24. #elif defined(Q_OS_WIN)
  25. g_updateManager = new UpdateManagerWin32(nullptr);
  26. #else
  27. g_updateManager = new UpdateManager(nullptr);
  28. #endif
  29. }
  30. return g_updateManager;
  31. }
  32. ///////////////////////////////////////////////////////////////////////////////////////////////////
  33. QString UpdateManager::HaveUpdate()
  34. {
  35. QDir updateDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/updates/");
  36. if (!updateDir.exists())
  37. {
  38. QLOG_DEBUG() << "No Update directory found, exiting";
  39. return "";
  40. }
  41. QStringList nonAppliedUpdates;
  42. // sort update directories, sort by the newest directory first, that way
  43. // we apply the latest update downloaded.
  44. //
  45. foreach (const QString& dir, updateDir.entryList(QDir::NoDotAndDotDot | QDir::Dirs, QDir::Time))
  46. {
  47. // check if this version has been applied
  48. QString readyFile(GetPath("_readyToApply", dir, false));
  49. QString packagesDir(GetPath("packages", dir, false));
  50. QLOG_DEBUG() << "Checking for:" << readyFile;
  51. QDir packageDir(GetPath("packages", dir, false));
  52. if (QFile::exists(readyFile))
  53. {
  54. QLOG_DEBUG() << dir << "is not applied";
  55. return dir;
  56. }
  57. else if (packageDir.exists())
  58. {
  59. QLOG_DEBUG() << "Removing old update packages in dir:" << dir;
  60. if (!packageDir.removeRecursively())
  61. {
  62. QLOG_WARN() << "Failed to remove old update packages in dir:" << dir;
  63. }
  64. }
  65. }
  66. QLOG_DEBUG() << "No valid/applicable update found.";
  67. return "";
  68. }
  69. ///////////////////////////////////////////////////////////////////////////////////////////////////
  70. bool UpdateManager::applyUpdate(const QString& version)
  71. {
  72. // make sure we have a manifest for this version.
  73. QLOG_DEBUG() << "Applying Update to version" << version;
  74. QString manifestPath = GetPath("manifest.xml.bz2", version, false);
  75. QString packagePath = QFileInfo(manifestPath).dir().absolutePath() + "/packages";
  76. if (!QFile(manifestPath).exists() || !QDir(packagePath).exists())
  77. {
  78. QLOG_ERROR() << "Could not find:" << manifestPath << "or" << packagePath;
  79. return false;
  80. }
  81. QString updaterName("updater");
  82. #ifdef Q_OS_WIN
  83. updaterName = "updater.exe";
  84. #endif
  85. QFile updaterFile(Paths::resourceDir(updaterName));
  86. if (!updaterFile.exists())
  87. {
  88. QLOG_ERROR() << "Missing updater:" << updaterFile.fileName();
  89. return false;
  90. }
  91. // copy the updater to a temporary directory so that we don't overwrite it.
  92. QString updaterPath = QDir::temp().absoluteFilePath(updaterName);
  93. // we need to remove it first, since QFile::copy() will fail otherwise.
  94. if (QFile::exists(updaterPath))
  95. {
  96. if (!QFile::remove(updaterPath))
  97. {
  98. QLOG_DEBUG() << "Failed to remove updater from " << updaterPath;
  99. }
  100. }
  101. if (!QFile::copy(updaterFile.fileName(), updaterPath))
  102. {
  103. QLOG_ERROR() << "Failed to copy the updater to:" << updaterPath;
  104. return false;
  105. }
  106. QStringList args;
  107. args << "--script=" + manifestPath;
  108. args << "--package-dir=" + packagePath;
  109. args << "--auto-close";
  110. #ifdef Q_OS_MAC
  111. args << "--install-dir=" + QDir(QCoreApplication::applicationDirPath() + "/../../").absolutePath();
  112. #else
  113. args << "--install-dir=" + QDir(QCoreApplication::applicationDirPath()).absolutePath();
  114. #endif
  115. args << "--wait=" + QString::number(QCoreApplication::applicationPid());
  116. // beyond this point we don't want to try to install this update again.
  117. QFile::remove(GetPath("_readyToApply", version, false));
  118. QLOG_DEBUG() << "Executing:" << updaterPath << args;
  119. auto process = new QProcess(nullptr);
  120. if (process->startDetached(updaterPath, args, QDir::temp().absolutePath()))
  121. {
  122. QLOG_DEBUG() << "Updater running, shutting down Plex Media Player";
  123. return true;
  124. }
  125. QLOG_ERROR() << "Failed to execute the updater";
  126. return false;
  127. }
  128. ///////////////////////////////////////////////////////////////////////////////////////////////////
  129. QString UpdateManager::GetPath(const QString& file, const QString& version, bool package)
  130. {
  131. QString filePath(file);
  132. // put the packages in the packages subdir.
  133. if (package)
  134. filePath = "packages/" + file;
  135. return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/updates/" + version + "/" + filePath;
  136. }
  137. ///////////////////////////////////////////////////////////////////////////////////////////////////
  138. void UpdateManager::doUpdate(const QString& version)
  139. {
  140. QLOG_DEBUG() << "Update competed, restarting system";
  141. if (!applyUpdate(version))
  142. {
  143. QLOG_ERROR() "Failed to apply update";
  144. }
  145. else
  146. {
  147. QLOG_DEBUG() "Update was applied successfully";
  148. }
  149. HelperLauncher::Get().stop();
  150. SystemComponent::Get().exit();
  151. }
  152. /////////////////////////////////////////////////////////////////////////////////////////
  153. bool UpdateManager::CheckForUpdates()
  154. {
  155. QString updateVersion = Get()->HaveUpdate();
  156. if (!updateVersion.isEmpty())
  157. {
  158. QLOG_DEBUG() << "We want to apply update:" << updateVersion;
  159. // if this call succeeds we need to shut down and let
  160. // the updater do it's work. Otherwise we'll just
  161. // start the application as normal and pretend that
  162. // nothing happened
  163. //
  164. if (Get()->applyUpdate(updateVersion))
  165. return true;
  166. }
  167. return false;
  168. }