aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Kampas <martin.kampas@jolla.com>2018-02-21 11:31:04 +0100
committerSvetlana Abramenkova <sabramenkova@luxoft.com>2018-06-14 08:11:51 +0000
commit4433fffbdec06241dcbb57c52c26d15bc4007e28 (patch)
tree11d2361a335acbcc2945d62cf5ac322b5fab427c
parent3e8e1de30c09fda84a66c31df1ac28ee33689ad1 (diff)
Allow to limit the number of watched directories
Consider starting bench e.g. in home directory. Different limitation on the number of watches applies depending on the platform. On linux the limit is per-user. Change-Id: If7a8cf6e3caa47ebaeb8cbd1fdc28d34d4d330b9 Reviewed-by: Svetlana Abramenkova <sabramenkova@luxoft.com>
-rw-r--r--src/bench/main.cpp14
-rw-r--r--src/bench/mainwindow.cpp77
-rw-r--r--src/bench/options.cpp11
-rw-r--r--src/bench/options.h4
-rw-r--r--src/livehubengine.cpp74
-rw-r--r--src/livehubengine.h15
-rw-r--r--src/watcher.cpp108
-rw-r--r--src/watcher.h17
-rw-r--r--src/widgets/workspaceview.cpp2
9 files changed, 301 insertions, 21 deletions
diff --git a/src/bench/main.cpp b/src/bench/main.cpp
index 9336b33..bf12122 100644
--- a/src/bench/main.cpp
+++ b/src/bench/main.cpp
@@ -36,6 +36,7 @@
#include "hostmanager.h"
#include "hostmodel.h"
+#include "livehubengine.h"
#include "options.h"
#include "mainwindow.h"
#include "qmllive_version.h"
@@ -211,6 +212,8 @@ void Application::parseArguments(const QStringList &arguments, Options *options)
parser.addOption(remoteOnlyOption);
QCommandLineOption pingOption("ping", "just check if there is a bench running and accepting remote connections.");
parser.addOption(pingOption);
+ QCommandLineOption maxWatchesOption("maxdirwatch", "limit the number of directories to watch for changes", "number", QString::number(options->maximumWatches()));
+ parser.addOption(maxWatchesOption);
parser.process(arguments);
@@ -237,6 +240,15 @@ void Application::parseArguments(const QStringList &arguments, Options *options)
parser.showHelp(-1);
}
+ if (parser.isSet(maxWatchesOption)) {
+ bool ok;
+ int value = parser.value(maxWatchesOption).toInt(&ok);
+ if (!ok) {
+ qWarning() << "Invalid argument to --maxdirwatch option";
+ parser.showHelp(-1);
+ }
+ options->setMaximumWatches(value);
+ }
options->setPluginPath(parser.value(pluginPathOption));
options->setImportPaths(parser.values(importPathOption));
@@ -417,6 +429,8 @@ void MasterApplication::listenForArguments()
void MasterApplication::applyOptions(const Options &options)
{
+ LiveHubEngine::setMaximumWatches(options.maximumWatches());
+
if (!options.workspace().isEmpty())
m_window->setWorkspace(QDir(options.workspace()).absolutePath(), false);
diff --git a/src/bench/mainwindow.cpp b/src/bench/mainwindow.cpp
index 61924aa..bd7063a 100644
--- a/src/bench/mainwindow.cpp
+++ b/src/bench/mainwindow.cpp
@@ -49,6 +49,46 @@
#include "hostdiscoverymanager.h"
#include "options.h"
+class ErrorBar : public QFrame
+{
+ Q_OBJECT
+
+public:
+ ErrorBar(QWidget *parent = 0)
+ : QFrame(parent)
+ {
+ setFrameShape(QFrame::StyledPanel);
+ setAutoFillBackground(true);
+ QPalette p = palette();
+ p.setColor(QPalette::Window, Qt::red);
+ setPalette(p);
+
+ auto layout = new QHBoxLayout(this);
+ layout->setContentsMargins(4, 4, 4, 4);
+
+ m_label = new QLabel;
+ m_label->setWordWrap(true);
+ layout->addWidget(m_label);
+
+ auto button = new QToolButton;
+ button->setAutoRaise(true);
+ button->setIcon(QIcon(":images/refresh.svg"));
+ connect(button, &QAbstractButton::clicked, this, &ErrorBar::retry);
+ layout->addWidget(button);
+ }
+
+ void setError(const QString &errorString)
+ {
+ m_label->setText(errorString);
+ setVisible(!errorString.isEmpty());
+ }
+
+signals:
+ void retry();
+
+private:
+ QLabel *m_label;
+};
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@@ -132,9 +172,42 @@ void MainWindow::setupWorkspaceView()
{
m_workspaceDock = new QDockWidget("Workspace", this);
m_workspaceDock->setObjectName("workspace");
- m_workspaceDock->setWidget(m_workspace);
m_workspaceDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_workspaceDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
+
+ auto contents = new QWidget;
+ auto layout = new QVBoxLayout(contents);
+ layout->setContentsMargins(1, 1, 1, 1);
+ layout->setSpacing(1);
+
+ auto errorBar = new ErrorBar;
+ layout->addWidget(errorBar);
+
+ auto updateErrorBar = [this, errorBar]() {
+ QString error;
+ switch (m_hub->error()) {
+ case LiveHubEngine::NoError:
+ break;
+ case LiveHubEngine::WatcherMaximumReached:
+ error = tr("Unable to monitor file changes: The configured limit of %1 directories was exceeded.")
+ .arg(LiveHubEngine::maximumWatches());
+ break;
+ case LiveHubEngine::WatcherSystemError:
+ error = tr("Unable to monitor file changes. System limit exceeded?");
+ break;
+ }
+ errorBar->setError(error);
+ };
+ updateErrorBar();
+ connect(m_hub, &LiveHubEngine::errorChanged, errorBar, updateErrorBar);
+
+ connect(errorBar, &ErrorBar::retry, this, [this]() {
+ m_hub->setWorkspace(m_hub->workspace());
+ });
+
+ layout->addWidget(m_workspace);
+
+ m_workspaceDock->setWidget(contents);
addDockWidget(Qt::LeftDockWidgetArea, m_workspaceDock);
}
@@ -517,3 +590,5 @@ void MainWindow::stayOnTop()
}
show();
}
+
+#include "mainwindow.moc"
diff --git a/src/bench/options.cpp b/src/bench/options.cpp
index 5baedc2..1e1f28b 100644
--- a/src/bench/options.cpp
+++ b/src/bench/options.cpp
@@ -37,6 +37,7 @@ Options::Options(QObject *parent)
, m_remoteOnly(false)
, m_ping(false)
, m_stayOnTop(false)
+ , m_maximumWatches(100)
{
}
@@ -174,3 +175,13 @@ void Options::setHostsToProbe(const QStringList &hostNames)
{
m_hostsToProbe = hostNames;
}
+
+int Options::maximumWatches() const
+{
+ return m_maximumWatches;
+}
+
+void Options::setMaximumWatches(int maximumWatches)
+{
+ m_maximumWatches = maximumWatches;
+}
diff --git a/src/bench/options.h b/src/bench/options.h
index e7c84bd..a0ab44f 100644
--- a/src/bench/options.h
+++ b/src/bench/options.h
@@ -86,6 +86,9 @@ public:
QStringList hostsToProbe() const;
void setHostsToProbe(const QStringList &hostNames);
+ int maximumWatches() const;
+ void setMaximumWatches(int maximumWatches);
+
private:
bool m_noRemote;
bool m_remoteOnly;
@@ -98,5 +101,6 @@ private:
QList<HostOptions> m_hostsToAdd;
QStringList m_hostsToRemove;
QStringList m_hostsToProbe;
+ int m_maximumWatches;
};
diff --git a/src/livehubengine.cpp b/src/livehubengine.cpp
index 39208bf..91c65dc 100644
--- a/src/livehubengine.cpp
+++ b/src/livehubengine.cpp
@@ -48,6 +48,18 @@
*/
/*!
+ \enum LiveHubEngine::Error
+ \brief Describes error state of an engine
+
+ \value NoError
+ No error
+ \value WatcherMaximumReached
+ The maximum number of watches set with setMaximumWatches() was exceeded
+ \value WatcherSystemError
+ Watching a directory for changes failed for an unspecified reason
+ */
+
+/*!
* Standard constructor using \a parent as parent
*/
LiveHubEngine::LiveHubEngine(QObject *parent)
@@ -56,6 +68,7 @@ LiveHubEngine::LiveHubEngine(QObject *parent)
, m_filePublishingActive(false)
{
connect(m_watcher, &Watcher::directoriesChanged, this, &LiveHubEngine::directoriesChanged);
+ connect(m_watcher, &Watcher::errorChanged, this, &LiveHubEngine::watcherErrorChanged);
}
/*!
@@ -95,6 +108,38 @@ LiveDocument LiveHubEngine::activePath() const
}
/*!
+ * Returns true if error() is not NoError
+ */
+bool LiveHubEngine::hasError()
+{
+ return m_error != NoError;
+}
+
+/*!
+ * Returns current Error
+ */
+LiveHubEngine::Error LiveHubEngine::error()
+{
+ return m_error;
+}
+
+/*!
+ * Returns the maximum number of watched directories
+ */
+int LiveHubEngine::maximumWatches()
+{
+ return Watcher::maximumWatches();
+}
+
+/*!
+ * Sets the maximum number of watched directories to \a maximumWatches
+ */
+void LiveHubEngine::setMaximumWatches(int maximumWatches)
+{
+ Watcher::setMaximumWatches(maximumWatches);
+}
+
+/*!
* Handles watcher changes signals.
*/
void LiveHubEngine::directoriesChanged(const QStringList &changes)
@@ -110,6 +155,31 @@ void LiveHubEngine::directoriesChanged(const QStringList &changes)
}
/*!
+ * Handles watcher error signals
+ */
+void LiveHubEngine::watcherErrorChanged()
+{
+ Error newError = NoError;
+ switch (m_watcher->error()) {
+ case Watcher::NoError:
+ newError = NoError;
+ break;
+ case Watcher::MaximumReached:
+ newError = WatcherMaximumReached;
+ break;
+ case Watcher::SystemError:
+ newError = WatcherSystemError;
+ break;
+ }
+
+ if (newError == m_error)
+ return;
+
+ m_error = newError;
+ emit errorChanged();
+}
+
+/*!
* Publish the whole workspace to a connected node.
*/
void LiveHubEngine::publishWorkspace()
@@ -186,3 +256,7 @@ void LiveHubEngine::setFilePublishingActive(bool on)
* The signal is emitted when the workspace identified by \a workspace has changed
*/
+/*!
+ * \fn void LiveHubEngine::errorChanged()
+ * The signal is emitted when the error state desctibed by error() changed
+ */
diff --git a/src/livehubengine.h b/src/livehubengine.h
index 266e07e..eba7203 100644
--- a/src/livehubengine.h
+++ b/src/livehubengine.h
@@ -43,11 +43,23 @@ class QMLLIVESHARED_EXPORT LiveHubEngine : public QObject
{
Q_OBJECT
public:
+ enum Error {
+ NoError,
+ WatcherMaximumReached,
+ WatcherSystemError,
+ };
+
explicit LiveHubEngine(QObject *parent = 0);
void setWorkspace(const QString& path);
QString workspace() const;
LiveDocument activePath() const;
+
+ bool hasError();
+ Error error();
+
+ static int maximumWatches();
+ static void setMaximumWatches(int maximumWatches);
public Q_SLOTS:
void setActivePath(const LiveDocument& path);
void setFilePublishingActive(bool on);
@@ -59,13 +71,16 @@ Q_SIGNALS:
void fileChanged(const LiveDocument& document);
void activateDocument(const LiveDocument& document);
void workspaceChanged(const QString& workspace);
+ void errorChanged();
private Q_SLOTS:
void directoriesChanged(const QStringList& changes);
+ void watcherErrorChanged();
private:
void publishDirectory(const QString& dirPath, bool fileChange);
private:
Watcher *m_watcher;
bool m_filePublishingActive;
LiveDocument m_activePath;
+ Error m_error = NoError;
};
diff --git a/src/watcher.cpp b/src/watcher.cpp
index 2be3abb..4bfb3b1 100644
--- a/src/watcher.cpp
+++ b/src/watcher.cpp
@@ -41,6 +41,20 @@
*/
/*!
+ \enum Watcher::Error
+ \brief Describes error state of a Watcher
+
+ \value NoError
+ No error
+ \value MaximumReached
+ The maximum number of watches set with setMaximumWatches() was exceeded
+ \value SystemError
+ QFileSystemWatcher::addPath failed for an unspecified reason
+ */
+
+int Watcher::s_maximumWatches = -1;
+
+/*!
Default Constructor using parent as parent
*/
Watcher::Watcher(QObject *parent)
@@ -63,12 +77,8 @@ Watcher::Watcher(QObject *parent)
void Watcher::setDirectory(const QString &path)
{
m_rootDir = QDir(path);
- if (!m_watcher->directories().isEmpty()) {
- m_watcher->removePaths(m_watcher->directories());
- }
- if (!m_watcher->files().isEmpty()) {
- m_watcher->removePaths(m_watcher->files());
- }
+ removeAllPaths();
+ setError(NoError);
addDirectoriesRecursively(m_rootDir.absolutePath());
}
@@ -81,28 +91,90 @@ QString Watcher::directory() const
}
/*!
+ \fn Watcher::maximumWatches()
+
+ Returns the maximum number of watched directories
+ */
+
+/*!
+ Sets the maximum number of watched directories
+
+ This will only take effect with next setDirectory() call.
+ */
+void Watcher::setMaximumWatches(int maximumWatches)
+{
+ s_maximumWatches = maximumWatches;
+}
+
+/*!
+ \fn Watcher::hasError() const
+
+ Returns true if error() is not NoError
+ */
+
+/*!
+ \fn Watcher::error() const
+
+ Describes the current error state of this watcher
+ */
+
+/*!
+ \fn Watcher::errorChanged()
+
+ Notifies about error() change
+ */
+
+/*!
Add path and all it's SubDirectory to the internal used QFileSystemWatcher
*/
void Watcher::addDirectoriesRecursively(const QString &path)
{
// qDebug() << "scan: " << path;
- if (!m_watcher->directories().contains(path)) {
- m_watcher->addPath(path);
- }
+ addDirectory(path);
QDirIterator iter(path, QDir::Dirs|QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
- while (iter.hasNext()) {
+ while (iter.hasNext() && !hasError()) {
QDir entry(iter.next());
- if (!m_watcher->directories().contains(entry.absolutePath())) {
- m_watcher->addPath(entry.absolutePath());
+ addDirectory(entry.absolutePath());
+ }
+}
- //If we couldn't add it we reached the filesystem limit
- if (!m_watcher->directories().contains(entry.absolutePath())) {
- qWarning() << "Watcher limit reached. Please reduce the number of files you are watching !!!";
- return;
- }
- }
+void Watcher::addDirectory(const QString &path)
+{
+ if (m_watcher->directories().contains(path))
+ return;
+
+ if (s_maximumWatches > 0 &&
+ m_watcher->directories().count() + m_watcher->files().count() > s_maximumWatches) {
+ removeAllPaths();
+ setError(MaximumReached);
+ return;
}
+ m_watcher->addPath(path);
+
+ if (!m_watcher->directories().contains(path)) {
+ removeAllPaths();
+ setError(SystemError);
+ }
+}
+
+void Watcher::removeAllPaths()
+{
+ if (!m_watcher->directories().isEmpty()) {
+ m_watcher->removePaths(m_watcher->directories());
+ }
+ if (!m_watcher->files().isEmpty()) {
+ m_watcher->removePaths(m_watcher->files());
+ }
+}
+
+void Watcher::setError(Watcher::Error error)
+{
+ if (m_error == error)
+ return;
+
+ m_error = error;
+ emit errorChanged();
}
void Watcher::recordChange(const QString &path)
diff --git a/src/watcher.h b/src/watcher.h
index a17e28a..434f552 100644
--- a/src/watcher.h
+++ b/src/watcher.h
@@ -37,20 +37,35 @@ class Watcher : public QObject
{
Q_OBJECT
public:
+ enum Error {
+ NoError,
+ MaximumReached,
+ SystemError,
+ };
+
explicit Watcher(QObject *parent = 0);
void setDirectory(const QString& path);
QString directory() const;
+ bool hasError() const { return m_error != NoError; }
+ Error error() const { return m_error; }
+ static int maximumWatches() { return s_maximumWatches; }
+ static void setMaximumWatches(int maximumWatches);
private Q_SLOTS:
void recordChange(const QString &path);
void notifyChanges();
Q_SIGNALS:
void directoriesChanged(const QStringList& changes);
-
+ void errorChanged();
private:
void addDirectoriesRecursively(const QString& path);
+ void addDirectory(const QString &path);
+ void removeAllPaths();
+ void setError(Error error);
+ static int s_maximumWatches;
QFileSystemWatcher *m_watcher;
QDir m_rootDir;
QTimer *m_waitTimer;
QStringList m_changes;
+ Error m_error = NoError;
};
diff --git a/src/widgets/workspaceview.cpp b/src/widgets/workspaceview.cpp
index a1f26f8..44e621a 100644
--- a/src/widgets/workspaceview.cpp
+++ b/src/widgets/workspaceview.cpp
@@ -73,7 +73,7 @@ WorkspaceView::WorkspaceView(QWidget *parent)
// setup layout
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(m_view);
- layout->setMargin(1);
+ layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
m_view->setDragEnabled(true);