diff options
author | Christian Kandeler <christian.kandeler@digia.com> | 2014-08-14 16:35:26 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@digia.com> | 2014-08-20 17:12:35 +0200 |
commit | 3957eac2205256ebe7784d2bc95fc4913c52801e (patch) | |
tree | 651350b27c92fac9d8f5cec0361501f35e896b4b | |
parent | af0e67f574ba294915881cf64b0d3ba64fc10d45 (diff) |
Use modified product names for build directories.
Users should be able to use any product name they want. In particular,
they should not be limited by what the file system supports; this is why
we have the "targetName" property. However, we currently subvert this by
using the product name as-is in the build directory. Instead, we now use
a super-safe version of the product name consisting only of selected
ASCII characters and make it unique by appending a hash of the original
name.
Change-Id: I3acf06d83a1c8a8c0a4716a7ac47a5bf8652075d
Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
-rw-r--r-- | src/lib/corelib/language/language.cpp | 19 | ||||
-rw-r--r-- | src/lib/corelib/language/language.h | 2 | ||||
-rw-r--r-- | src/lib/corelib/language/moduleloader.cpp | 4 | ||||
-rw-r--r-- | src/lib/corelib/language/tst_language.cpp | 8 | ||||
-rw-r--r-- | src/lib/corelib/language/tst_language.h | 1 | ||||
-rw-r--r-- | tests/auto/api/tst_api.cpp | 10 | ||||
-rw-r--r-- | tests/auto/shared.h | 22 |
7 files changed, 48 insertions, 18 deletions
diff --git a/src/lib/corelib/language/language.cpp b/src/lib/corelib/language/language.cpp index 5c5fac445..de56b169f 100644 --- a/src/lib/corelib/language/language.cpp +++ b/src/lib/corelib/language/language.cpp @@ -46,6 +46,7 @@ #include <tools/persistence.h> #include <tools/qbsassert.h> +#include <QCryptographicHash> #include <QDir> #include <QDirIterator> #include <QMap> @@ -755,6 +756,24 @@ QStringList ResolvedProduct::generatedFiles(const QString &baseFile, const FileT return QStringList(); } +QString ResolvedProduct::deriveBuildDirectoryName(const QString &name, const QString &profile) +{ + QString dirName = uniqueName(name, profile); + const QByteArray hash = QCryptographicHash::hash(dirName.toUtf8(), QCryptographicHash::Sha1); + for (int i = 0; i < dirName.count(); ++i) { + QCharRef ch = dirName[i]; + const char c = ch.toLatin1(); + + // Let's be conservative with what characters we allow for file system entries. + const bool okChar = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') || c == '_' || c == '.'; + if (!okChar) + ch = QChar::fromLatin1('_'); + } + dirName.append(QLatin1Char('.')).append(QString::fromLatin1(hash.toHex().left(8))); + return dirName; +} + QString ResolvedProduct::buildDirectory() const { const QString result = productProperties.value(QLatin1String("buildDirectory")).toString(); diff --git a/src/lib/corelib/language/language.h b/src/lib/corelib/language/language.h index 145e4d22b..9b43119c7 100644 --- a/src/lib/corelib/language/language.h +++ b/src/lib/corelib/language/language.h @@ -397,6 +397,8 @@ public: QString uniqueName() const; QStringList generatedFiles(const QString &baseFile, const FileTags &tags) const; + + static QString deriveBuildDirectoryName(const QString &name, const QString &profile); QString buildDirectory() const; private: diff --git a/src/lib/corelib/language/moduleloader.cpp b/src/lib/corelib/language/moduleloader.cpp index 8893ad14e..5e074cd1a 100644 --- a/src/lib/corelib/language/moduleloader.cpp +++ b/src/lib/corelib/language/moduleloader.cpp @@ -413,10 +413,10 @@ void ModuleLoader::initProductProperties(const ProjectContext *project, Item *it const QString productName = m_evaluator->stringValue(item, QLatin1String("name")); const QString profile = m_evaluator->stringValue(item, QLatin1String("profile")); QBS_CHECK(!profile.isEmpty()); - const QString uniqueName = ResolvedProduct::uniqueName(productName, profile); + const QString buildDir = ResolvedProduct::deriveBuildDirectoryName(productName, profile); item->setProperty(QLatin1String("buildDirectory"), VariantValue::create( - FileInfo::resolvePath(project->buildDirectory, uniqueName))); + FileInfo::resolvePath(project->buildDirectory, buildDir))); item->setProperty(QLatin1String("sourceDirectory"), VariantValue::create( diff --git a/src/lib/corelib/language/tst_language.cpp b/src/lib/corelib/language/tst_language.cpp index 8a16643e2..b3156251b 100644 --- a/src/lib/corelib/language/tst_language.cpp +++ b/src/lib/corelib/language/tst_language.cpp @@ -120,12 +120,6 @@ void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool * } } -QString TestLanguage::buildDir(const SetupProjectParameters ¶ms) const -{ - return FileInfo::resolvePath(params.buildRoot(), params.topLevelProfile() - + QLatin1Char('-') + params.buildVariant()); -} - #define HANDLE_INIT_CLEANUP_DATATAGS(fn) {\ bool handled;\ handleInitCleanupDataTags(fn, &handled);\ @@ -1133,7 +1127,7 @@ void TestLanguage::productDirectories() QVERIFY(product); const QVariantMap config = product->productProperties; QCOMPARE(config.value(QLatin1String("buildDirectory")).toString(), - buildDir(defaultParameters) + QLatin1Char('/') + product->uniqueName()); + product->buildDirectory()); QCOMPARE(config.value(QLatin1String("sourceDirectory")).toString(), testDataDir()); } catch (const ErrorInfo &e) { diff --git a/src/lib/corelib/language/tst_language.h b/src/lib/corelib/language/tst_language.h index 7e3ce5df5..f0050957c 100644 --- a/src/lib/corelib/language/tst_language.h +++ b/src/lib/corelib/language/tst_language.h @@ -60,7 +60,6 @@ private: ResolvedModuleConstPtr findModuleByName(ResolvedProductPtr product, const QString &name); QVariant productPropertyValue(ResolvedProductPtr product, QString propertyName); void handleInitCleanupDataTags(const char *projectFileName, bool *handled); - QString buildDir(const SetupProjectParameters ¶ms) const; private slots: void initTestCase(); diff --git a/tests/auto/api/tst_api.cpp b/tests/auto/api/tst_api.cpp index 0786a6e8a..4c747929d 100644 --- a/tests/auto/api/tst_api.cpp +++ b/tests/auto/api/tst_api.cpp @@ -1051,16 +1051,18 @@ void TestApi::multiArch() QScopedPointer<qbs::BuildJob> buildJob(project.buildAllProducts(qbs::BuildOptions())); waitForFinished(buildJob.data()); QVERIFY2(!buildJob->error().hasError(), qPrintable(buildJob->error().toString())); - const QString outputBaseDir(setupParams.buildRoot() + "/qbs_autotests-debug"); - QFile p1HostArtifact(outputBaseDir + "/p1.host/host+target.output"); + const QString outputBaseDir = setupParams.buildRoot() + '/'; + QFile p1HostArtifact(outputBaseDir + + relativeProductBuildDir("p1", "host") + "/host+target.output"); QVERIFY2(p1HostArtifact.exists(), qPrintable(p1HostArtifact.fileName())); QVERIFY2(p1HostArtifact.open(QIODevice::ReadOnly), qPrintable(p1HostArtifact.errorString())); QCOMPARE(p1HostArtifact.readAll().constData(), "host-arch"); - QFile p1TargetArtifact(outputBaseDir + "/p1.target/host+target.output"); + QFile p1TargetArtifact(outputBaseDir + relativeProductBuildDir("p1", "target") + + "/host+target.output"); QVERIFY2(p1TargetArtifact.exists(), qPrintable(p1TargetArtifact.fileName())); QVERIFY2(p1TargetArtifact.open(QIODevice::ReadOnly), qPrintable(p1TargetArtifact.errorString())); QCOMPARE(p1TargetArtifact.readAll().constData(), "target-arch"); - QFile p2Artifact(outputBaseDir + "/p2.host/host-tool.output"); + QFile p2Artifact(outputBaseDir + relativeProductBuildDir("p2", "host") + "/host-tool.output"); QVERIFY2(p2Artifact.exists(), qPrintable(p2Artifact.fileName())); QVERIFY2(p2Artifact.open(QIODevice::ReadOnly), qPrintable(p2Artifact.errorString())); QCOMPARE(p2Artifact.readAll().constData(), "host-arch"); diff --git a/tests/auto/shared.h b/tests/auto/shared.h index 7ec6ed5ea..01621d772 100644 --- a/tests/auto/shared.h +++ b/tests/auto/shared.h @@ -31,6 +31,7 @@ #include <tools/hostosinfo.h> +#include <QCryptographicHash> #include <QFile> #include <QFileInfo> #include <QtTest> @@ -56,14 +57,27 @@ inline bool regularFileExists(const QString &filePath) return fi.exists() && fi.isFile(); } -inline QString uniqueProductName(const QString &productName) +inline QString uniqueProductName(const QString &productName, const QString &_profileName) { - return productName + '.' + profileName(); + const QString p = _profileName.isEmpty() ? profileName() : _profileName; + return productName + '.' + p; } -inline QString relativeProductBuildDir(const QString &productName) +inline QString relativeProductBuildDir(const QString &productName, + const QString &profileName = QString()) { - return relativeBuildDir() + '/' + uniqueProductName(productName); + const QString fullName = uniqueProductName(productName, profileName); + QString dirName = fullName; + for (int i = 0; i < dirName.count(); ++i) { + QCharRef c = dirName[i]; + const bool okChar = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') + || (c >= 'a' && c <= 'z') || c == '_' || c == '.'; + if (!okChar) + c = QChar::fromLatin1('_'); + } + const QByteArray hash = QCryptographicHash::hash(fullName.toUtf8(), QCryptographicHash::Sha1); + dirName.append('.').append(hash.toHex().left(8)); + return relativeBuildDir() + '/' + dirName; } inline QString relativeExecutableFilePath(const QString &productName) |