forked from qt-creator/qt-creator
QbsProjectManager: Fix handling of overlapping parse requests.
The current code simply asserts when a new parse request comes in while parsing. However, that condition is easily triggered, for instance if a project file is saved to disk during a parse operation. Such updates currently have no effect at all (other than triggering an error message). Instead, we now cancel the old parse job and start a new one. Change-Id: If2eeb93b85b5163dcea99785a0fc89a254d082db Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
This commit is contained in:
@@ -102,6 +102,7 @@ QbsProject::QbsProject(QbsManager *manager, const QString &fileName) :
|
|||||||
m_qbsUpdateFutureInterface(0),
|
m_qbsUpdateFutureInterface(0),
|
||||||
m_forceParsing(false),
|
m_forceParsing(false),
|
||||||
m_parsingScheduled(false),
|
m_parsingScheduled(false),
|
||||||
|
m_cancelingParsing(false),
|
||||||
m_currentBc(0)
|
m_currentBc(0)
|
||||||
{
|
{
|
||||||
m_parsingDelay.setInterval(1000); // delay parsing by 1s.
|
m_parsingDelay.setInterval(1000); // delay parsing by 1s.
|
||||||
@@ -275,12 +276,23 @@ void QbsProject::handleQbsParsingDone(bool success)
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(m_qbsProjectParser, return);
|
QTC_ASSERT(m_qbsProjectParser, return);
|
||||||
|
|
||||||
|
// If this parse operation was canceled, start a new one right away, ignoring the old result.
|
||||||
|
if (m_cancelingParsing) {
|
||||||
|
m_cancelingParsing = false;
|
||||||
|
m_qbsProjectParser->deleteLater();
|
||||||
|
m_qbsProjectParser = 0;
|
||||||
|
parseCurrentBuildConfiguration(m_forceParsing);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
generateErrors(m_qbsProjectParser->error());
|
generateErrors(m_qbsProjectParser->error());
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
m_qbsProject = m_qbsProjectParser->qbsProject();
|
m_qbsProject = m_qbsProjectParser->qbsProject();
|
||||||
QTC_CHECK(m_qbsProject.isValid());
|
QTC_CHECK(m_qbsProject.isValid());
|
||||||
readQbsData();
|
readQbsData();
|
||||||
|
} else {
|
||||||
|
m_qbsUpdateFutureInterface->reportCanceled();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_qbsProjectParser->deleteLater();
|
m_qbsProjectParser->deleteLater();
|
||||||
@@ -369,12 +381,27 @@ void QbsProject::parseCurrentBuildConfiguration(bool force)
|
|||||||
m_parsingScheduled = false;
|
m_parsingScheduled = false;
|
||||||
if (!m_forceParsing)
|
if (!m_forceParsing)
|
||||||
m_forceParsing = force;
|
m_forceParsing = force;
|
||||||
|
if (m_cancelingParsing)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!activeTarget())
|
if (!activeTarget())
|
||||||
return;
|
return;
|
||||||
QbsBuildConfiguration *bc = qobject_cast<QbsBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
|
QbsBuildConfiguration *bc = qobject_cast<QbsBuildConfiguration *>(activeTarget()->activeBuildConfiguration());
|
||||||
if (!bc)
|
if (!bc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// New parse requests override old ones.
|
||||||
|
// NOTE: We need to wait for the current operation to finish, since otherwise there could
|
||||||
|
// be a conflict. Consider the case where the old qbs::ProjectSetupJob is writing
|
||||||
|
// to the build graph file when the cancel request comes in. If we don't wait for
|
||||||
|
// acknowledgment, it might still be doing that when the new one already reads from the
|
||||||
|
// same file.
|
||||||
|
if (m_qbsProjectParser) {
|
||||||
|
m_cancelingParsing = true;
|
||||||
|
m_qbsProjectParser->cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
parse(bc->qbsConfiguration(), bc->environment(), bc->buildDirectory().toString());
|
parse(bc->qbsConfiguration(), bc->environment(), bc->buildDirectory().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ private:
|
|||||||
QFutureInterface<bool> *m_qbsUpdateFutureInterface;
|
QFutureInterface<bool> *m_qbsUpdateFutureInterface;
|
||||||
bool m_forceParsing;
|
bool m_forceParsing;
|
||||||
bool m_parsingScheduled;
|
bool m_parsingScheduled;
|
||||||
|
bool m_cancelingParsing;
|
||||||
|
|
||||||
QFuture<void> m_codeModelFuture;
|
QFuture<void> m_codeModelFuture;
|
||||||
|
|
||||||
|
|||||||
@@ -136,6 +136,12 @@ bool QbsProjectParser::parse(const QVariantMap &config, const Environment &env,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QbsProjectParser::cancel()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_qbsSetupProjectJob, return);
|
||||||
|
m_qbsSetupProjectJob->cancel();
|
||||||
|
}
|
||||||
|
|
||||||
qbs::Project QbsProjectParser::qbsProject() const
|
qbs::Project QbsProjectParser::qbsProject() const
|
||||||
{
|
{
|
||||||
return m_project;
|
return m_project;
|
||||||
@@ -153,8 +159,8 @@ void QbsProjectParser::handleQbsParsingDone(bool success)
|
|||||||
m_project = m_qbsSetupProjectJob->project();
|
m_project = m_qbsSetupProjectJob->project();
|
||||||
m_error = m_qbsSetupProjectJob->error();
|
m_error = m_qbsSetupProjectJob->error();
|
||||||
|
|
||||||
if (!success)
|
// Do not report the operation as canceled here, as we might want to make overlapping
|
||||||
m_fi->reportCanceled();
|
// parses appear atomic to the user.
|
||||||
|
|
||||||
emit done(success);
|
emit done(success);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ public:
|
|||||||
void setForced(bool);
|
void setForced(bool);
|
||||||
|
|
||||||
bool parse(const QVariantMap &config, const Utils::Environment &env, const QString &dir);
|
bool parse(const QVariantMap &config, const Utils::Environment &env, const QString &dir);
|
||||||
|
void cancel();
|
||||||
|
|
||||||
qbs::Project qbsProject() const;
|
qbs::Project qbsProject() const;
|
||||||
qbs::ErrorInfo error();
|
qbs::ErrorInfo error();
|
||||||
|
|||||||
Reference in New Issue
Block a user