diff options
Diffstat (limited to 'src/lib/corelib/loader/loader.cpp')
-rw-r--r-- | src/lib/corelib/loader/loader.cpp | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/src/lib/corelib/loader/loader.cpp b/src/lib/corelib/loader/loader.cpp new file mode 100644 index 000000000..82358c96d --- /dev/null +++ b/src/lib/corelib/loader/loader.cpp @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qbs. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "loader.h" + +#include "projectresolver.h" +#include "projecttreebuilder.h" + +#include <language/evaluator.h> +#include <language/itempool.h> +#include <language/language.h> +#include <language/scriptengine.h> +#include <logging/translator.h> +#include <tools/fileinfo.h> +#include <tools/profile.h> +#include <tools/progressobserver.h> +#include <tools/qbsassert.h> +#include <tools/settings.h> +#include <tools/setupprojectparameters.h> +#include <tools/stringconstants.h> + +#include <QtCore/qdir.h> +#include <QtCore/qobject.h> + +namespace qbs { +namespace Internal { + +Loader::Loader(ScriptEngine *engine, Logger logger) + : m_logger(std::move(logger)) + , m_progressObserver(nullptr) + , m_engine(engine) +{ + m_logger.storeWarnings(); +} + +void Loader::setProgressObserver(ProgressObserver *observer) +{ + m_progressObserver = observer; +} + +void Loader::setSearchPaths(const QStringList &_searchPaths) +{ + QStringList searchPaths; + for (const QString &searchPath : _searchPaths) { + if (!FileInfo::exists(searchPath)) { + m_logger.qbsWarning() << Tr::tr("Search path '%1' does not exist.") + .arg(QDir::toNativeSeparators(searchPath)); + } else { + searchPaths += searchPath; + } + } + + m_searchPaths = searchPaths; +} + +void Loader::setOldProjectProbes(const std::vector<ProbeConstPtr> &oldProbes) +{ + m_oldProjectProbes = oldProbes; +} + +void Loader::setOldProductProbes(const QHash<QString, std::vector<ProbeConstPtr>> &oldProbes) +{ + m_oldProductProbes = oldProbes; +} + +void Loader::setStoredProfiles(const QVariantMap &profiles) +{ + m_storedProfiles = profiles; +} + +void Loader::setStoredModuleProviderInfo(const StoredModuleProviderInfo &providerInfo) +{ + m_storedModuleProviderInfo = providerInfo; +} + +TopLevelProjectPtr Loader::loadProject(const SetupProjectParameters &_parameters) +{ + SetupProjectParameters parameters = _parameters; + + if (parameters.topLevelProfile().isEmpty()) { + Settings settings(parameters.settingsDirectory()); + QString profileName = settings.defaultProfile(); + if (profileName.isEmpty()) { + m_logger.qbsDebug() << Tr::tr("No profile specified and no default profile exists. " + "Using default property values."); + profileName = Profile::fallbackName(); + } + parameters.setTopLevelProfile(profileName); + parameters.expandBuildConfiguration(); + } + + setupProjectFilePath(parameters); + QBS_CHECK(QFileInfo(parameters.projectFilePath()).isAbsolute()); + m_logger.qbsDebug() << "Using project file '" + << QDir::toNativeSeparators(parameters.projectFilePath()) << "'."; + + m_engine->setEnvironment(parameters.adjustedEnvironment()); + m_engine->checkAndClearException({}); + m_engine->clearImportsCache(); + m_engine->clearRequestedProperties(); + m_engine->enableProfiling(parameters.logElapsedTime()); + m_logger.clearWarnings(); + EvalContextSwitcher evalContextSwitcher(m_engine, EvalContext::PropertyEvaluation); + + // At this point, we cannot set a sensible total effort, because we know nothing about + // the project yet. That's why we use a placeholder here, so the user at least + // sees that an operation is starting. The real total effort will be set later when + // we have enough information. + if (m_progressObserver) { + m_progressObserver->initialize(Tr::tr("Resolving project for configuration %1") + .arg(TopLevelProject::deriveId(parameters.finalBuildConfigurationTree())), 1); + m_progressObserver->setScriptEngine(m_engine); + } + + const FileTime resolveTime = FileTime::currentTime(); + Evaluator evaluator(m_engine); + ItemPool pool; + ProjectTreeBuilder projectTreeBuilder(parameters, pool, evaluator, m_logger); + projectTreeBuilder.setProgressObserver(m_progressObserver); + projectTreeBuilder.setSearchPaths(m_searchPaths); + projectTreeBuilder.setOldProjectProbes(m_oldProjectProbes); + projectTreeBuilder.setOldProductProbes(m_oldProductProbes); + projectTreeBuilder.setLastResolveTime(m_lastResolveTime); + projectTreeBuilder.setStoredProfiles(m_storedProfiles); + projectTreeBuilder.setStoredModuleProviderInfo(m_storedModuleProviderInfo); + const ProjectTreeBuilder::Result loadResult = projectTreeBuilder.load(); + ProjectResolver resolver(&evaluator, loadResult, std::move(parameters), m_logger); + resolver.setProgressObserver(m_progressObserver); + TopLevelProjectPtr project = resolver.resolve(); + project->lastStartResolveTime = resolveTime; + project->lastEndResolveTime = FileTime::currentTime(); + + // E.g. if the top-level project is disabled. + if (m_progressObserver) + m_progressObserver->setFinished(); + + return project; +} + +void Loader::setupProjectFilePath(SetupProjectParameters ¶meters) +{ + QString projectFilePath = parameters.projectFilePath(); + if (projectFilePath.isEmpty()) + projectFilePath = QDir::currentPath(); + const QFileInfo projectFileInfo(projectFilePath); + if (!projectFileInfo.exists()) + throw ErrorInfo(Tr::tr("Project file '%1' cannot be found.").arg(projectFilePath)); + if (projectFileInfo.isRelative()) + projectFilePath = projectFileInfo.absoluteFilePath(); + if (projectFileInfo.isFile()) { + parameters.setProjectFilePath(projectFilePath); + return; + } + if (!projectFileInfo.isDir()) + throw ErrorInfo(Tr::tr("Project file '%1' has invalid type.").arg(projectFilePath)); + + const QStringList &actualFileNames + = QDir(projectFilePath).entryList(StringConstants::qbsFileWildcards(), QDir::Files); + if (actualFileNames.empty()) { + QString error; + if (parameters.projectFilePath().isEmpty()) + error = Tr::tr("No project file given and none found in current directory.\n"); + else + error = Tr::tr("No project file found in directory '%1'.").arg(projectFilePath); + throw ErrorInfo(error); + } + if (actualFileNames.size() > 1) { + throw ErrorInfo(Tr::tr("More than one project file found in directory '%1'.") + .arg(projectFilePath)); + } + projectFilePath.append(QLatin1Char('/')).append(actualFileNames.front()); + + projectFilePath = QDir::current().filePath(projectFilePath); + projectFilePath = QDir::cleanPath(projectFilePath); + parameters.setProjectFilePath(projectFilePath); +} + +} // namespace Internal +} // namespace qbs |