aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@digia.com>2014-07-30 16:19:22 +0200
committerChristian Kandeler <christian.kandeler@digia.com>2014-07-30 16:57:02 +0200
commit59aed7c423ab1ff8e19d34736619cb128cc8b49a (patch)
tree013307f4243703e342bc89fcdc62ad4647cd5a9f
parentc598241085cd191c3914a4b614f219e7a9a55bbf (diff)
Invalidate project after certain unsuccessful re-resolving attempts.
Namely, if the build data has been mangled by the re-resolving attempt. Change-Id: Ibe020a6bda38a335f95e2d2cef4f37fac3199a7d Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
-rw-r--r--src/lib/corelib/api/jobs.cpp6
-rw-r--r--src/lib/corelib/api/project.cpp7
-rw-r--r--tests/auto/api/api.qbs2
-rw-r--r--tests/auto/api/testdata/project-invalidation/project.early-error.qbs6
-rw-r--r--tests/auto/api/testdata/project-invalidation/project.late-error.qbs13
-rw-r--r--tests/auto/api/testdata/project-invalidation/project.no-error.qbs5
-rw-r--r--tests/auto/api/tst_api.cpp32
-rw-r--r--tests/auto/api/tst_api.h1
8 files changed, 68 insertions, 4 deletions
diff --git a/src/lib/corelib/api/jobs.cpp b/src/lib/corelib/api/jobs.cpp
index 6b8cf702e..00269d947 100644
--- a/src/lib/corelib/api/jobs.cpp
+++ b/src/lib/corelib/api/jobs.cpp
@@ -252,8 +252,12 @@ void SetupProjectJob::finish()
// The invariant is that there must always be at most one valid Project object
// for the same build directory, so that exclusive ownership of the build graph lock
// is ensured.
- if (m_existingProject.isValid() && !error().hasError())
+ // We also need to invalidate the project if an error has occurred after the build data was
+ // already transferred.
+ if (m_existingProject.isValid()
+ && (!error().hasError() || !m_existingProject.d->internalProject->buildData)) {
m_existingProject.d->internalProject.clear();
+ }
}
/*!
diff --git a/src/lib/corelib/api/project.cpp b/src/lib/corelib/api/project.cpp
index 3e5ea76d9..93daf433f 100644
--- a/src/lib/corelib/api/project.cpp
+++ b/src/lib/corelib/api/project.cpp
@@ -717,8 +717,11 @@ Project &Project::operator=(const Project &other)
* track the results of the operation.
* If the function is called on a valid \c Project object, the build graph will not be loaded
* from a file, but will be taken from the existing project. In that case, if resolving
- * finishes successfully, the existing project will be invalidated. If resolving fails, the
- * existing \c Project object stays as it is.
+ * finishes successfully, the existing project will be invalidated. If resolving fails, qbs will
+ * try to keep the existing project valid. However, under certain circumstances, resolving the new
+ * project will fail at a time where existing project data has already been touched, in which case
+ * the existing project has to be invalidated (this could be avoided, but it would hurt performance).
+ * So after an unsuccessful re-resolve job, the existing project may or may not be valid anymore.
* \note The qbs plugins will only be loaded once. As a result, the value of
* \c parameters.pluginPaths will only have an effect the first time this function is called.
* Similarly, the value of \c parameters.searchPaths will not have an effect if
diff --git a/tests/auto/api/api.qbs b/tests/auto/api/api.qbs
index df42afc89..343325469 100644
--- a/tests/auto/api/api.qbs
+++ b/tests/auto/api/api.qbs
@@ -2,7 +2,7 @@ import "../autotest.qbs" as AutoTest
AutoTest {
testName: "api"
- files: ["tst_api.h", "tst_api.cpp"]
+ files: ["../shared.h", "tst_api.h", "tst_api.cpp"]
cpp.defines: base
.concat(['SRCDIR="' + path + '"'])
.concat(project.enableProjectFileUpdates ? ["QBS_ENABLE_PROJECT_FILE_UPDATES"] : [])
diff --git a/tests/auto/api/testdata/project-invalidation/project.early-error.qbs b/tests/auto/api/testdata/project-invalidation/project.early-error.qbs
new file mode 100644
index 000000000..ecc76c816
--- /dev/null
+++ b/tests/auto/api/testdata/project-invalidation/project.early-error.qbs
@@ -0,0 +1,6 @@
+import qbs
+
+Product {
+ type: "mytype"
+ files: "nosuchfile.txt"
+}
diff --git a/tests/auto/api/testdata/project-invalidation/project.late-error.qbs b/tests/auto/api/testdata/project-invalidation/project.late-error.qbs
new file mode 100644
index 000000000..b55979ec7
--- /dev/null
+++ b/tests/auto/api/testdata/project-invalidation/project.late-error.qbs
@@ -0,0 +1,13 @@
+import qbs
+
+Product {
+ type: "mytype"
+
+ Transformer {
+ Artifact {
+ filePath: "blubb"
+ fileTags: "mytype"
+ }
+ prepare: []
+ }
+}
diff --git a/tests/auto/api/testdata/project-invalidation/project.no-error.qbs b/tests/auto/api/testdata/project-invalidation/project.no-error.qbs
new file mode 100644
index 000000000..099553ffc
--- /dev/null
+++ b/tests/auto/api/testdata/project-invalidation/project.no-error.qbs
@@ -0,0 +1,5 @@
+import qbs
+
+Product {
+ type: "mytype"
+}
diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp
index cc85fd704..fd2968441 100644
--- a/tests/auto/api/tst_api.cpp
+++ b/tests/auto/api/tst_api.cpp
@@ -29,6 +29,8 @@
#include "tst_api.h"
+#include "../shared.h"
+
#include <api/jobs.h>
#include <api/project.h>
#include <api/projectdata.h>
@@ -760,6 +762,36 @@ void TestApi::nonexistingProjectPropertyFromCommandLine()
qPrintable(job->error().toString()));
}
+void TestApi::projectInvalidation()
+{
+ qbs::SetupProjectParameters setupParams = defaultSetupParameters();
+ setupParams.setRestoreBehavior(qbs::SetupProjectParameters::RestoreAndTrackChanges);
+ const QString projectDirPath = QDir::cleanPath(m_workingDataDir + "/project-invalidation");
+ setupParams.setProjectFilePath(projectDirPath + "/project.qbs");
+ QDir::setCurrent(projectDirPath);
+ QVERIFY(QFile::copy("project.no-error.qbs", "project.qbs"));
+ QScopedPointer<qbs::SetupProjectJob> setupJob(qbs::Project().setupProject(setupParams,
+ m_logSink, 0));
+ waitForFinished(setupJob.data());
+ QVERIFY2(!setupJob->error().hasError(), qPrintable(setupJob->error().toString()));
+ qbs::Project project = setupJob->project();
+ QVERIFY(project.isValid());
+ waitForNewTimestamp();
+ QVERIFY(QFile::remove("project.qbs"));
+ QVERIFY(QFile::copy("project.early-error.qbs", "project.qbs"));
+ setupJob.reset(project.setupProject(setupParams, m_logSink, 0));
+ waitForFinished(setupJob.data());
+ QVERIFY(setupJob->error().hasError());
+ QVERIFY(project.isValid()); // Error in Loader, old project still valid.
+ waitForNewTimestamp();
+ QVERIFY(QFile::remove("project.qbs"));
+ QVERIFY(QFile::copy("project.late-error.qbs", "project.qbs"));
+ setupJob.reset(project.setupProject(setupParams, m_logSink, 0));
+ waitForFinished(setupJob.data());
+ QVERIFY(setupJob->error().hasError());
+ QVERIFY(!project.isValid()); // Error in build data re-resolving, old project not valid anymore.
+}
+
void TestApi::projectLocking()
{
qbs::SetupProjectParameters setupParams = defaultSetupParameters();
diff --git a/tests/auto/api/tst_api.h b/tests/auto/api/tst_api.h
index 473b20c80..8285f1b53 100644
--- a/tests/auto/api/tst_api.h
+++ b/tests/auto/api/tst_api.h
@@ -63,6 +63,7 @@ private slots:
void multiArch();
void nonexistingProjectPropertyFromProduct();
void nonexistingProjectPropertyFromCommandLine();
+ void projectInvalidation();
void projectLocking();
void references();
void sourceFileInBuildDir();