Merge pull request #3472 from owncloud/linux_restart_on_new_version

On Linux restart if new version is found on disk
This commit is contained in:
Daniel Molkentin 2015-08-06 17:47:10 +02:00
Родитель cad2d639af 72b2c52e15
Коммит 6a20ea5e73
10 изменённых файлов: 137 добавлений и 2 удалений

Просмотреть файл

@ -88,6 +88,7 @@ Application::Application(int &argc, char **argv) :
_gui(0), _gui(0),
_theme(Theme::instance()), _theme(Theme::instance()),
_helpOnly(false), _helpOnly(false),
_versionOnly(false),
_showLogWindow(false), _showLogWindow(false),
_logExpire(0), _logExpire(0),
_logFlush(false), _logFlush(false),
@ -104,7 +105,7 @@ Application::Application(int &argc, char **argv) :
#endif #endif
parseOptions(arguments()); parseOptions(arguments());
//no need to waste time; //no need to waste time;
if ( _helpOnly ) return; if ( _helpOnly || _versionOnly ) return;
if (isRunning()) if (isRunning())
return; return;
@ -174,6 +175,11 @@ Application::Application(int &argc, char **argv) :
// Cleanup at Quit. // Cleanup at Quit.
connect (this, SIGNAL(aboutToQuit()), SLOT(slotCleanup())); connect (this, SIGNAL(aboutToQuit()), SLOT(slotCleanup()));
// remember the version of the currently running binary. On Linux it might happen that the
// package management updates the package while the app is running. This is detected in the
// updater slot: If the installed binary on the hd has a different version than the one
// running, the running app is restart. That happens in folderman.
_runningAppVersion = Utility::versionOfInstalledBinary();
} }
Application::~Application() Application::~Application()
@ -211,6 +217,16 @@ void Application::slotCleanup()
_gui->deleteLater(); _gui->deleteLater();
} }
if( Utility::isLinux() ) {
// on linux, check if the installed binary is still the same version
// as the one that is running. If not, restart if possible.
const QByteArray fsVersion = Utility::versionOfInstalledBinary();
if( !(fsVersion.isEmpty() || _runningAppVersion.isEmpty()) && fsVersion != _runningAppVersion ) {
_folderManager->slotScheduleAppRestart();
}
}
void Application::slotCheckConnection() void Application::slotCheckConnection()
{ {
auto list = AccountManager::instance()->accounts(); auto list = AccountManager::instance()->accounts();
@ -339,6 +355,8 @@ void Application::parseOptions(const QStringList &options)
} }
} else if (option == QLatin1String("--debug")) { } else if (option == QLatin1String("--debug")) {
_debugMode = true; _debugMode = true;
} else if (option == QLatin1String("--version")) {
_versionOnly = true;
} else { } else {
showHint("Unrecognized option '" + option.toStdString() + "'"); showHint("Unrecognized option '" + option.toStdString() + "'");
} }
@ -389,6 +407,17 @@ void Application::showHelp()
displayHelpText(helpText); displayHelpText(helpText);
} }
void Application::showVersion()
{
QString helpText;
QTextStream stream(&helpText);
stream << _theme->appName().toLatin1().constData()
<< QLatin1String(" version ")
<< _theme->version().toLatin1().constData() << endl;
displayHelpText(helpText);
}
void Application::showHint(std::string errorHint) void Application::showHint(std::string errorHint)
{ {
static QString binName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); static QString binName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
@ -485,6 +514,11 @@ bool Application::giveHelp()
return _helpOnly; return _helpOnly;
} }
bool Application::versionOnly()
{
return _versionOnly;
}
void Application::showSettingsDialog() void Application::showSettingsDialog()
{ {
_gui->slotShowSettings(); _gui->slotShowSettings();

Просмотреть файл

@ -58,6 +58,8 @@ public:
void showHelp(); void showHelp();
void showHint(std::string errorHint); void showHint(std::string errorHint);
bool debugMode(); bool debugMode();
bool versionOnly(); // only display the version?
void showVersion();
void showSettingsDialog(); void showSettingsDialog();
@ -93,6 +95,7 @@ private:
Theme *_theme; Theme *_theme;
bool _helpOnly; bool _helpOnly;
bool _versionOnly;
// options from command line: // options from command line:
bool _showLogWindow; bool _showLogWindow;
@ -102,6 +105,7 @@ private:
bool _logFlush; bool _logFlush;
bool _userTriggeredConnect; bool _userTriggeredConnect;
bool _debugMode; bool _debugMode;
QByteArray _runningAppVersion;
ClientProxy _proxy; ClientProxy _proxy;

Просмотреть файл

@ -54,7 +54,8 @@ static qint64 msBetweenRequestAndSync = 2000;
FolderMan::FolderMan(QObject *parent) : FolderMan::FolderMan(QObject *parent) :
QObject(parent), QObject(parent),
_currentSyncFolder(0), _currentSyncFolder(0),
_syncEnabled( true ) _syncEnabled( true ),
_appRestartRequired(false)
{ {
Q_ASSERT(!_instance); Q_ASSERT(!_instance);
_instance = this; _instance = this;
@ -473,6 +474,12 @@ void FolderMan::slotScheduleAllFolders()
} }
} }
void FolderMan::slotScheduleAppRestart()
{
_appRestartRequired = true;
qDebug() << "## Application restart requested!";
}
/* /*
* if a folder wants to be synced, it calls this slot and is added * if a folder wants to be synced, it calls this slot and is added
* to the queue. The slot to actually start a sync is called afterwards. * to the queue. The slot to actually start a sync is called afterwards.
@ -540,6 +547,11 @@ void FolderMan::slotRunOneEtagJob()
} }
if (_currentEtagJob.isNull()) { if (_currentEtagJob.isNull()) {
qDebug() << "No more remote ETag check jobs to schedule."; qDebug() << "No more remote ETag check jobs to schedule.";
/* now it might be a good time to check for restarting... */
if( _currentSyncFolder == NULL && _appRestartRequired ) {
restartApplication();
}
} else { } else {
qDebug() << "Scheduling" << alias << "to check remote ETag"; qDebug() << "Scheduling" << alias << "to check remote ETag";
_currentEtagJob->start(); // on destroy/end it will continue the queue via slotEtagJobDestroyed _currentEtagJob->start(); // on destroy/end it will continue the queue via slotEtagJobDestroyed
@ -1164,5 +1176,19 @@ QString FolderMan::checkPathValidityForNewFolder(const QString& path, bool forNe
} }
void FolderMan::restartApplication()
{
if( Utility::isLinux() ) {
// restart:
qDebug() << "### Restarting application NOW, PID" << qApp->applicationPid() << "is ending.";
qApp->quit();
QStringList args = qApp->arguments();
QString prg = args.takeFirst();
QProcess::startDetached(prg, args);
} else {
qDebug() << "On this platform we do not restart.";
}
}
} // namespace OCC } // namespace OCC

Просмотреть файл

@ -148,6 +148,11 @@ public slots:
*/ */
void slotAccountStateChanged(); void slotAccountStateChanged();
/**
* restart the client as soon as it is possible, ie. no folders syncing.
*/
void slotScheduleAppRestart();
private slots: private slots:
// slot to take the next folder from queue and start syncing. // slot to take the next folder from queue and start syncing.
void slotStartScheduledFolderSync(); void slotStartScheduledFolderSync();
@ -176,6 +181,9 @@ private:
QString getBackupName( QString fullPathName ) const; QString getBackupName( QString fullPathName ) const;
void registerFolderMonitor( Folder *folder ); void registerFolderMonitor( Folder *folder );
// restarts the application (Linux only)
void restartApplication();
QString unescapeAlias( const QString& ) const; QString unescapeAlias( const QString& ) const;
QSet<Folder*> _disabledFolders; QSet<Folder*> _disabledFolders;
@ -196,6 +204,8 @@ private:
/** When the timer expires one of the scheduled syncs will be started. */ /** When the timer expires one of the scheduled syncs will be started. */
QTimer _startScheduledSyncTimer; QTimer _startScheduledSyncTimer;
bool _appRestartRequired;
static FolderMan *_instance; static FolderMan *_instance;
explicit FolderMan(QObject *parent = 0); explicit FolderMan(QObject *parent = 0);
friend class OCC::Application; friend class OCC::Application;

Просмотреть файл

@ -59,6 +59,10 @@ int main(int argc, char **argv)
app.showHelp(); app.showHelp();
return 0; return 0;
} }
if( app.versionOnly() ) {
app.showVersion();
return 0;
}
// check a environment variable for core dumps // check a environment variable for core dumps
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX

Просмотреть файл

@ -393,6 +393,35 @@ void Utility::crash()
*a = 1; *a = 1;
} }
// read the output of the owncloud --version command from the owncloud
// version that is on disk. This works for most versions of the client,
// because clients that do not yet know the --version flag return the
// version in the first line of the help output :-)
//
// This version only delivers output on linux, as Mac and Win get their
// restarting from the installer.
QByteArray Utility::versionOfInstalledBinary( const QString& command )
{
QByteArray re;
if( isLinux() ) {
QString binary(command);
if( binary.isEmpty() ) {
binary = qApp->arguments()[0];
}
QStringList params;
params << QLatin1String("--version");
QProcess process;
process.start(binary, params);
process.waitForFinished(); // sets current thread to sleep and waits for pingProcess end
re = process.readAllStandardOutput();
int newline = re.indexOf(QChar('\n'));
if( newline > 0 ) {
re.truncate( newline );
}
}
return re;
}
static const char STOPWATCH_END_TAG[] = "_STOPWATCH_END"; static const char STOPWATCH_END_TAG[] = "_STOPWATCH_END";
void Utility::StopWatch::start() void Utility::StopWatch::start()

Просмотреть файл

@ -98,6 +98,13 @@ namespace Utility
// if false, the two cases are two different files. // if false, the two cases are two different files.
OWNCLOUDSYNC_EXPORT bool fsCasePreserving(); OWNCLOUDSYNC_EXPORT bool fsCasePreserving();
// Call the given command with the switch --version and retrun the first line
// of the output.
// If command is empty, the function calls the running application which, on
// Linux, might have changed while this one is running.
// For Mac and Windows, it returns QString()
OWNCLOUDSYNC_EXPORT QByteArray versionOfInstalledBinary(const QString& command = QString() );
class OWNCLOUDSYNC_EXPORT StopWatch { class OWNCLOUDSYNC_EXPORT StopWatch {
private: private:
QHash<QString, quint64> _lapTimes; QHash<QString, quint64> _lapTimes;

Просмотреть файл

@ -26,6 +26,8 @@ if( UNIX AND NOT APPLE )
owncloud_add_test(InotifyWatcher "${FolderWatcher_SRC}") owncloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
endif(UNIX AND NOT APPLE) endif(UNIX AND NOT APPLE)
configure_file(oc_bin.h.in oc_bin.h)
owncloud_add_test(CSyncSqlite "") owncloud_add_test(CSyncSqlite "")
owncloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp) owncloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
owncloud_add_test(OwnSql "") owncloud_add_test(OwnSql "")

3
test/oc_bin.h.in Normal file
Просмотреть файл

@ -0,0 +1,3 @@
#define OWNCLOUD_BIN "@CMAKE_BINARY_DIR@/bin/owncloud"

Просмотреть файл

@ -11,6 +11,8 @@
#include "utility.h" #include "utility.h"
#include "oc_bin.h"
using namespace OCC::Utility; using namespace OCC::Utility;
class TestUtility : public QObject class TestUtility : public QObject
@ -100,6 +102,20 @@ private slots:
} }
void testVersionOfInstalledBinary()
{
if( isLinux() ) {
QString ver = versionOfInstalledBinary(OWNCLOUD_BIN);
qDebug() << "Version of installed ownCloud Binary: " << ver;
QVERIFY( !ver.isEmpty());
QRegExp rx( "ownCloud version \\d+\\.\\d+\\.\\d+.+" );
QVERIFY( rx.exactMatch(ver));
} else {
QVERIFY( versionOfInstalledBinary().isEmpty());
}
}
}; };
#endif #endif