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
commit 6a20ea5e73
10 changed files with 137 additions and 2 deletions

View file

@ -88,6 +88,7 @@ Application::Application(int &argc, char **argv) :
_gui(0),
_theme(Theme::instance()),
_helpOnly(false),
_versionOnly(false),
_showLogWindow(false),
_logExpire(0),
_logFlush(false),
@ -104,7 +105,7 @@ Application::Application(int &argc, char **argv) :
#endif
parseOptions(arguments());
//no need to waste time;
if ( _helpOnly ) return;
if ( _helpOnly || _versionOnly ) return;
if (isRunning())
return;
@ -174,6 +175,11 @@ Application::Application(int &argc, char **argv) :
// Cleanup at Quit.
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()
@ -211,6 +217,16 @@ void Application::slotCleanup()
_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()
{
auto list = AccountManager::instance()->accounts();
@ -339,6 +355,8 @@ void Application::parseOptions(const QStringList &options)
}
} else if (option == QLatin1String("--debug")) {
_debugMode = true;
} else if (option == QLatin1String("--version")) {
_versionOnly = true;
} else {
showHint("Unrecognized option '" + option.toStdString() + "'");
}
@ -389,6 +407,17 @@ void Application::showHelp()
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)
{
static QString binName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
@ -485,6 +514,11 @@ bool Application::giveHelp()
return _helpOnly;
}
bool Application::versionOnly()
{
return _versionOnly;
}
void Application::showSettingsDialog()
{
_gui->slotShowSettings();

View file

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

View file

@ -54,7 +54,8 @@ static qint64 msBetweenRequestAndSync = 2000;
FolderMan::FolderMan(QObject *parent) :
QObject(parent),
_currentSyncFolder(0),
_syncEnabled( true )
_syncEnabled( true ),
_appRestartRequired(false)
{
Q_ASSERT(!_instance);
_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
* to the queue. The slot to actually start a sync is called afterwards.
@ -540,6 +547,11 @@ void FolderMan::slotRunOneEtagJob()
}
if (_currentEtagJob.isNull()) {
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 {
qDebug() << "Scheduling" << alias << "to check remote ETag";
_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

View file

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

View file

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

View file

@ -393,6 +393,35 @@ void Utility::crash()
*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";
void Utility::StopWatch::start()

View file

@ -98,6 +98,13 @@ namespace Utility
// if false, the two cases are two different files.
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 {
private:
QHash<QString, quint64> _lapTimes;

View file

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

3
test/oc_bin.h.in Normal file
View file

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

View file

@ -11,6 +11,8 @@
#include "utility.h"
#include "oc_bin.h"
using namespace OCC::Utility;
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