diff options
42 files changed, 1514 insertions, 527 deletions
diff --git a/src/app/qbs/commandlinefrontend.cpp b/src/app/qbs/commandlinefrontend.cpp index 8ac89d0b2..d734b9120 100644 --- a/src/app/qbs/commandlinefrontend.cpp +++ b/src/app/qbs/commandlinefrontend.cpp @@ -99,15 +99,15 @@ void CommandLineFrontend::start() const QString qbsRootPath = QDir::cleanPath(QCoreApplication::applicationDirPath() + QLatin1String("/../")); SetupProjectParameters params; - params.projectFilePath = m_parser.projectFilePath(); - params.buildRoot = QDir::currentPath(); - params.searchPaths = Preferences(m_settings).searchPaths(qbsRootPath); - params.pluginPaths = Preferences(m_settings).pluginPaths(qbsRootPath); - params.ignoreDifferentProjectFilePath = m_parser.force(); - params.dryRun = m_parser.dryRun(); - params.logElapsedTime = m_parser.logTime(); + params.setProjectFilePath(m_parser.projectFilePath()); + params.setBuildRoot(QDir::currentPath()); + params.setSearchPaths(Preferences(m_settings).searchPaths(qbsRootPath)); + params.setPluginPaths(Preferences(m_settings).pluginPaths(qbsRootPath)); + params.setIgnoreDifferentProjectFilePath(m_parser.force()); + params.setDryRun(m_parser.dryRun()); + params.setLogElapsedTime(m_parser.logTime()); foreach (const QVariantMap &buildConfig, m_parser.buildConfigurations()) { - params.buildConfiguration = buildConfig; + params.setBuildConfiguration(buildConfig); SetupProjectJob * const job = Project::setupProject(params, m_settings, ConsoleLogger::instance().logSink(), this); connectJob(job); @@ -236,15 +236,15 @@ void CommandLineFrontend::handleWarningReport(const qbs::Error &warning) void CommandLineFrontend::handleProcessResultReport(const qbs::ProcessResult &result) { - bool hasOutput = !result.stdOut.isEmpty() || !result.stdErr.isEmpty(); - if (!hasOutput && result.success) + bool hasOutput = !result.stdOut().isEmpty() || !result.stdErr().isEmpty(); + if (!hasOutput && result.success()) return; - (result.success ? qbsInfo() : qbsError()) - << result.binary << " " << result.arguments.join(QLatin1String(" ")) + (result.success() ? qbsInfo() : qbsError()) + << result.executableFilePath() << " " << result.arguments().join(QLatin1String(" ")) << (hasOutput ? QString::fromLatin1("\n") : QString()) - << (result.stdOut.isEmpty() ? QString() : result.stdOut.join(QLatin1String("\n"))) - << (result.stdErr.isEmpty() ? QString() : result.stdErr.join(QLatin1String("\n"))); + << (result.stdOut().isEmpty() ? QString() : result.stdOut().join(QLatin1String("\n"))) + << (result.stdErr().isEmpty() ? QString() : result.stdErr().join(QLatin1String("\n"))); } bool CommandLineFrontend::resolvingMultipleProjects() const @@ -395,7 +395,7 @@ int CommandLineFrontend::runTarget() Q_ASSERT(products.count() == 1); const ProductData productToRun = products.first(); const QString executableFilePath = project.targetExecutable(productToRun, - m_parser.installOptions().installRoot); + m_parser.installOptions().installRoot()); if (executableFilePath.isEmpty()) { throw Error(Tr::tr("Cannot run: Product '%1' is not an application.") .arg(productToRun.name())); diff --git a/src/app/qbs/parser/commandlineparser.cpp b/src/app/qbs/parser/commandlineparser.cpp index 1b8a657c6..cea0c8587 100644 --- a/src/app/qbs/parser/commandlineparser.cpp +++ b/src/app/qbs/parser/commandlineparser.cpp @@ -138,11 +138,11 @@ CleanOptions CommandLineParser::cleanOptions() const { Q_ASSERT(command() == CleanCommandType); CleanOptions options; - options.cleanType = d->optionPool.allArtifactsOption()->enabled() - ? CleanOptions::CleanupAll : CleanOptions::CleanupTemporaries; - options.dryRun = buildOptions().dryRun; - options.keepGoing = buildOptions().keepGoing; - options.logElapsedTime = logTime(); + options.setCleanType(d->optionPool.allArtifactsOption()->enabled() + ? CleanOptions::CleanupAll : CleanOptions::CleanupTemporaries); + options.setDryRun(buildOptions().dryRun()); + options.setKeepGoing(buildOptions().keepGoing()); + options.setLogElapsedTime(logTime()); return options; } @@ -150,16 +150,16 @@ InstallOptions CommandLineParser::installOptions() const { Q_ASSERT(command() == InstallCommandType || command() == RunCommandType); InstallOptions options; - options.removeFirst = d->optionPool.removeFirstoption()->enabled(); - options.installRoot = d->optionPool.installRootOption()->installRoot(); - if (!options.installRoot.isEmpty()) { - QFileInfo fi(options.installRoot); + options.setRemoveExistingInstallation(d->optionPool.removeFirstoption()->enabled()); + options.setInstallRoot(d->optionPool.installRootOption()->installRoot()); + if (!options.installRoot().isEmpty()) { + QFileInfo fi(options.installRoot()); if (!fi.isAbsolute()) - options.installRoot = fi.absoluteFilePath(); + options.setInstallRoot(fi.absoluteFilePath()); } - options.dryRun = buildOptions().dryRun; - options.keepGoing = buildOptions().keepGoing; - options.logElapsedTime = logTime(); + options.setDryRun(buildOptions().dryRun()); + options.setKeepGoing(buildOptions().keepGoing()); + options.setLogElapsedTime(logTime()); return options; } @@ -462,18 +462,19 @@ void CommandLineParser::CommandLineParserPrivate::setupProjectFile() void CommandLineParser::CommandLineParserPrivate::setupBuildOptions() { - buildOptions.dryRun = dryRun(); - buildOptions.changedFiles = optionPool.changedFilesOption()->arguments(); + buildOptions.setDryRun(dryRun()); + QStringList changedFiles = optionPool.changedFilesOption()->arguments(); QDir currentDir; - for (int i = 0; i < buildOptions.changedFiles.count(); ++i) { - QString &file = buildOptions.changedFiles[i]; + for (int i = 0; i < changedFiles.count(); ++i) { + QString &file = changedFiles[i]; file = QDir::fromNativeSeparators(currentDir.absoluteFilePath(file)); } - buildOptions.keepGoing = optionPool.keepGoingOption()->enabled(); + buildOptions.setChangedFiles(changedFiles); + buildOptions.setKeepGoing(optionPool.keepGoingOption()->enabled()); const JobsOption * jobsOption = optionPool.jobsOption(); - buildOptions.maxJobCount = jobsOption->jobCount() > 0 - ? jobsOption->jobCount() : Preferences(settings).jobs(); - buildOptions.logElapsedTime = logTime; + buildOptions.setMaxJobCount(jobsOption->jobCount() > 0 + ? jobsOption->jobCount() : Preferences(settings).jobs()); + buildOptions.setLogElapsedTime(logTime); } void CommandLineParser::CommandLineParserPrivate::setupProgress() diff --git a/src/app/qbs/status.cpp b/src/app/qbs/status.cpp index 2683d468a..c09190f5e 100644 --- a/src/app/qbs/status.cpp +++ b/src/app/qbs/status.cpp @@ -112,7 +112,7 @@ QStringList allFiles(const ProductData &product) int printStatus(const ProjectData &project) { - const QString projectFilePath = project.location().fileName; + const QString projectFilePath = project.location().fileName(); QString projectDirectory = QFileInfo(projectFilePath).dir().path(); int projectDirectoryPathLength = projectDirectory.length(); @@ -120,10 +120,12 @@ int printStatus(const ProjectData &project) QStringList missingFiles; foreach (const ProductData &product, project.products()) { qbsInfo() << "\nProduct: " << product.name() - << " (" << product.location().fileName << ":" << product.location().line << ")"; + << " (" << product.location().fileName() << ":" + << product.location().line() << ")"; foreach (const GroupData &group, product.groups()) { qbsInfo() << " Group: " << group.name() - << " (" << group.location().fileName << ":" << group.location().line << ")"; + << " (" << group.location().fileName() << ":" + << group.location().line() << ")"; QStringList sourceFiles = group.allFilePaths(); qSort(sourceFiles); foreach (const QString &sourceFile, sourceFiles) { diff --git a/src/lib/api/api.pri b/src/lib/api/api.pri index e82cf8382..61632356b 100644 --- a/src/lib/api/api.pri +++ b/src/lib/api/api.pri @@ -4,7 +4,8 @@ HEADERS += \ $$PWD/runenvironment.h \ $$PWD/jobs.h \ $$PWD/project.h \ - $$PWD/propertymap_p.h + $$PWD/propertymap_p.h \ + $$PWD/projectdata_p.h SOURCES += \ $$PWD/internaljobs.cpp \ diff --git a/src/lib/api/internaljobs.cpp b/src/lib/api/internaljobs.cpp index 5a721ba34..d6de8ce81 100644 --- a/src/lib/api/internaljobs.cpp +++ b/src/lib/api/internaljobs.cpp @@ -143,7 +143,7 @@ InternalSetupProjectJob::~InternalSetupProjectJob() void InternalSetupProjectJob::resolve(const SetupProjectParameters ¶meters) { m_parameters = parameters; - setTimed(parameters.logElapsedTime); + setTimed(parameters.logElapsedTime()); QTimer::singleShot(0, this, SLOT(start())); } @@ -197,19 +197,19 @@ void InternalSetupProjectJob::execute() m_project = loadResult.newlyResolvedProject; } else { Loader loader(evalContext->engine(), logger()); - loader.setSearchPaths(m_parameters.searchPaths); + loader.setSearchPaths(m_parameters.searchPaths()); loader.setProgressObserver(observer()); m_project = loader.loadProject(m_parameters); } if (m_project->products.isEmpty()) { throw Error(Tr::tr("Project '%1' does not contain products.") - .arg(m_parameters.projectFilePath)); + .arg(m_parameters.projectFilePath())); } } // copy the environment from the platform config into the project's config const QVariantMap platformEnvironment - = m_parameters.buildConfiguration.value(QLatin1String("environment")).toMap(); + = m_parameters.buildConfiguration().value(QLatin1String("environment")).toMap(); m_project->platformEnvironment = platformEnvironment; logger().qbsDebug() << QString::fromLocal8Bit("for %1:").arg(m_project->id()); @@ -227,7 +227,7 @@ void InternalSetupProjectJob::execute() BuildDataResolver::rescueBuildData(loadResult.loadedProject, m_project, logger()); } - if (!m_parameters.dryRun) + if (!m_parameters.dryRun()) storeBuildGraph(m_project); // The evalutation context cannot be re-used for building, which runs in a different thread. @@ -267,8 +267,8 @@ void InternalBuildJob::build(const ResolvedProjectPtr &project, const QList<ResolvedProductPtr> &products, const BuildOptions &buildOptions, const QProcessEnvironment &env) { - setup(project, products, buildOptions.dryRun); - setTimed(buildOptions.logElapsedTime); + setup(project, products, buildOptions.dryRun()); + setTimed(buildOptions.logElapsedTime()); m_executor = new Executor(logger()); m_executor->setProject(project); @@ -314,8 +314,8 @@ InternalCleanJob::InternalCleanJob(const Logger &logger, QObject *parent) void InternalCleanJob::clean(const ResolvedProjectPtr &project, const QList<ResolvedProductPtr> &products, const CleanOptions &options) { - setup(project, products, options.dryRun); - setTimed(options.logElapsedTime); + setup(project, products, options.dryRun()); + setTimed(options.logElapsedTime()); m_options = options; QTimer::singleShot(0, this, SLOT(start())); } @@ -358,7 +358,7 @@ void InternalInstallJob::install(const QList<ResolvedProductPtr> &products, { m_products = products; m_options = options; - setTimed(options.logElapsedTime); + setTimed(options.logElapsedTime()); QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection); } diff --git a/src/lib/api/project.cpp b/src/lib/api/project.cpp index dc5eebe25..b9820242f 100644 --- a/src/lib/api/project.cpp +++ b/src/lib/api/project.cpp @@ -31,6 +31,7 @@ #include "internaljobs.h" #include "jobs.h" #include "projectdata.h" +#include "projectdata_p.h" #include "propertymap_p.h" #include "runenvironment.h" #include <buildgraph/artifact.h> @@ -200,35 +201,35 @@ ResolvedProductPtr ProjectPrivate::internalProduct(const ProductData &product) c void ProjectPrivate::retrieveProjectData() { - m_projectData.m_location = internalProject->location; - m_projectData.m_buildDir = internalProject->buildDirectory; + m_projectData.d->location = internalProject->location; + m_projectData.d->buildDir = internalProject->buildDirectory; foreach (const ResolvedProductConstPtr &resolvedProduct, internalProject->products) { ProductData product; - product.m_name = resolvedProduct->name; - product.m_location = resolvedProduct->location; - product.m_fileTags = resolvedProduct->fileTags.toStringList(); - product.m_properties.d->m_map = resolvedProduct->properties; - product.m_isEnabled = resolvedProduct->enabled; + product.d->name = resolvedProduct->name; + product.d->location = resolvedProduct->location; + product.d->fileTags = resolvedProduct->fileTags.toStringList(); + product.d->properties.d->m_map = resolvedProduct->properties; + product.d->isEnabled = resolvedProduct->enabled; foreach (const GroupPtr &resolvedGroup, resolvedProduct->groups) { GroupData group; - group.m_name = resolvedGroup->name; - group.m_location = resolvedGroup->location; + group.d->name = resolvedGroup->name; + group.d->location = resolvedGroup->location; foreach (const SourceArtifactConstPtr &sa, resolvedGroup->files) - group.m_filePaths << sa->absoluteFilePath; + group.d->filePaths << sa->absoluteFilePath; if (resolvedGroup->wildcards) { foreach (const SourceArtifactConstPtr &sa, resolvedGroup->wildcards->files) - group.m_expandedWildcards << sa->absoluteFilePath; + group.d->expandedWildcards << sa->absoluteFilePath; } - qSort(group.m_filePaths); - qSort(group.m_expandedWildcards); - group.m_properties.d->m_map = resolvedGroup->properties; - group.m_isEnabled = resolvedGroup->enabled; - product.m_groups << group; + qSort(group.d->filePaths); + qSort(group.d->expandedWildcards); + group.d->properties.d->m_map = resolvedGroup->properties; + group.d->isEnabled = resolvedGroup->enabled; + product.d->groups << group; } - qSort(product.m_groups); - m_projectData.m_products << product; + qSort(product.d->groups); + m_projectData.d->products << product; } - qSort(m_projectData.m_products); + qSort(m_projectData.d->products); m_projectDataRetrieved = true; } @@ -325,10 +326,10 @@ SetupProjectJob *Project::setupProject(const SetupProjectParameters &_parameters Logger logger(logSink); SetupProjectJob * const job = new SetupProjectJob(logger, jobOwner); try { - loadPlugins(_parameters.pluginPaths, logger); + loadPlugins(_parameters.pluginPaths(), logger); SetupProjectParameters parameters = _parameters; - parameters.buildConfiguration - = expandBuildConfiguration(parameters.buildConfiguration, settings); + parameters.setBuildConfiguration(expandBuildConfiguration( + parameters.buildConfiguration(), settings)); job->resolve(parameters); } catch (const Error &error) { // Throwing from here would complicate the API, so let's report the error the same way diff --git a/src/lib/api/projectdata.cpp b/src/lib/api/projectdata.cpp index f228f997b..7b46f1829 100644 --- a/src/lib/api/projectdata.cpp +++ b/src/lib/api/projectdata.cpp @@ -28,6 +28,7 @@ ****************************************************************************/ #include "projectdata.h" +#include "projectdata_p.h" #include "propertymap_p.h" #include <language/propertymapinternal.h> #include <tools/propertyfinder.h> @@ -36,7 +37,98 @@ namespace qbs { -GroupData::GroupData() { } +/*! + * \class GroupData + * \brief The \c GroupData class corresponds to the Group item in a qbs source file. + */ + +GroupData::GroupData() : d(new Internal::GroupDataPrivate) +{ +} + +GroupData::GroupData(const GroupData &other) : d(other.d) +{ +} + +GroupData &GroupData::operator=(const GroupData &other) +{ + d = other.d; + return *this; +} + +GroupData::~GroupData() +{ +} + +/*! + * \brief The location at which the group is defined in the respective source file. + */ +CodeLocation GroupData::location() const +{ + return d->location; +} + +/*! + * \brief The name of the group. + */ +QString GroupData::name() const +{ + return d->name; +} + +/*! + * \brief The files listed in the group item's "files" binding. + * \note These do not include expanded wildcards. + * \sa GroupData::expandedWildcards + */ +QStringList GroupData::filePaths() const +{ + return d->filePaths; +} + +/*! + * \brief The list of files resulting from expanding all wildcard patterns in the group. + */ +QStringList GroupData::expandedWildcards() const +{ + return d->expandedWildcards; +} + +/*! + * \brief The set of properties valid in this group. + * Typically, most of them are inherited from the respective \c Product. + */ +PropertyMap GroupData::properties() const +{ + return d->properties; +} + +/*! + * \brief Returns true if this group is enabled in Qbs + * This method returns the "condition" property of the \c Group definition. If the group is enabled + * then the files in this group will be processed, provided the product it belongs to is also + * enabled. + * + * Note that a group can be enabled, even if the product it belongs to is not. In this case + * the files in the group will not be processed. + * \sa ProductData::isEnabled() + */ +bool GroupData::isEnabled() const +{ + return d->isEnabled; +} + +/*! + * \fn QStringList GroupData::allFilePaths() const + * \brief All files in this group, regardless of how whether they were given explicitly + * or via wildcards. + * \sa GroupData::filePaths + * \sa GroupData::expandedWildcards + */ +QStringList GroupData::allFilePaths() const +{ + return d->filePaths + d->expandedWildcards; +} bool operator==(const GroupData &lhs, const GroupData &rhs) { @@ -53,7 +145,82 @@ bool operator!=(const GroupData &lhs, const GroupData &rhs) return !(lhs == rhs); } -ProductData::ProductData() { } +/*! + * \class ProductData + * \brief The \c ProductData class corresponds to the Product item in a qbs source file. + */ + +ProductData::ProductData() : d(new Internal::ProductDataPrivate) +{ +} + +ProductData::ProductData(const ProductData &other) : d(other.d) +{ +} + +ProductData &ProductData::operator=(const ProductData &other) +{ + d = other.d; + return *this; +} + +ProductData::~ProductData() +{ +} + +/*! + * \brief The name of the product as given in the qbs source file. + */ +QString ProductData::name() const +{ + return d->name; +} + +/*! + * \brief The location at which the product is defined in the source file. + */ +CodeLocation ProductData::location() const +{ + return d->location; +} + +/*! + * \brief The file tags of this product. Corresponds to a Product's "type" property in + * a qbs source file. + */ +QStringList ProductData::fileTags() const +{ + return d->fileTags; +} + +/*! + * \brief The set of properties valid in this product. + * \note product properties can be overwritten in a group. + * \sa GroupData::properties() + */ +PropertyMap ProductData::properties() const +{ + return d->properties; +} + +/*! + * \brief The list of \c GroupData in this product. + */ +QList<GroupData> ProductData::groups() const +{ + return d->groups; +} + +/*! + * \brief Returns true if this Product is enabled in Qbs. + * This method returns the \c condition property of the \c Product definition. If a product is + * enabled, then it will be built in the current configuration. + * \sa GroupData::isEnabled() + */ +bool ProductData::isEnabled() const +{ + return d->isEnabled; +} bool operator==(const ProductData &lhs, const ProductData &rhs) { @@ -75,7 +242,58 @@ bool operator<(const GroupData &lhs, const GroupData &rhs) return lhs.name() < rhs.name(); } -ProjectData::ProjectData() { } +/*! + * \class ProjectData + * \brief The \c ProjectData class corresponds to the \c Project item in a qbs source file. + */ + +/*! + * \fn QList<ProductData> ProjectData::products() const + * \brief The products in this project. + */ + +ProjectData::ProjectData() : d(new Internal::ProjectDataPrivate) +{ +} + +ProjectData::ProjectData(const ProjectData &other) : d(other.d) +{ +} + +ProjectData &ProjectData::operator =(const ProjectData &other) +{ + d = other.d; + return *this; +} + +ProjectData::~ProjectData() +{ +} + +/*! + * \brief The location at which the project is defined in a qbs source file. + */ +CodeLocation ProjectData::location() const +{ + return d->location; +} + +/*! + * \brief The base directory under which the build artifacts of this project will be created. + */ +QString ProjectData::buildDirectory() const +{ + return d->buildDir; +} + +/*! + * The products in this project. + * \note This also includes disabled products. + */ +QList<ProductData> ProjectData::products() const +{ + return d->products; +} bool operator==(const ProjectData &lhs, const ProjectData &rhs) { @@ -215,124 +433,4 @@ bool operator!=(const PropertyMap &pm1, const PropertyMap &pm2) return !(pm1.d->m_map->value() == pm2.d->m_map->value()); } -/*! - * \class GroupData - * \brief The \c GroupData class corresponds to the Group item in a qbs source file. - */ - - /*! - * \fn QString GroupData::name() const - * \brief The name of the group. - */ - -/*! - * \fn int GroupData::qbsLine() const - * \brief The line at which the group is defined in the respective source file. - */ - - /*! - * \fn QStringList GroupData::filePaths() const - * \brief The files listed in the group item's "files" binding. - * Note that these do not include expanded wildcards. - * \sa GroupData::expandedWildcards - */ - -/*! - * \fn QStringList GroupData::expandedWildcards() const - * \brief The list of files resulting from expanding all wildcard patterns in the group. - */ - -/*! - * \fn QVariantMap GroupData::properties() const - * \brief The set of properties valid in this group. - * Typically, most of them are inherited from the respective Product. - */ - - /*! - * \fn QStringList GroupData::allFilePaths() const - * \brief All files in this group, regardless of how whether they were given explicitly - * or via wildcards. - * \sa GroupData::filePaths - * \sa GroupData::expandedWildcards - */ - -/*! - * \fn bool GroupData::isEnabled() const - * \brief Returns true if this Group is enabled in Qbs - * This method returns the "condition" property of the Group definition. If the group is enabled - * then the files in this Group will be processed, provided the Product it belongs to is also - * enabled. - * - * Note that a Group can be enabled, even if the Product it belongs to is not. In this case - * the files in the Group will not be processed. - * \sa ProductData::isEnabled() - */ - -/*! - * \class ProductData - * \brief The \c ProductData class corresponds to the Product item in a qbs source file. - */ - -/*! - * \fn QString ProductData::name() const - * \brief The name of the product as given in the qbs source file. - */ - -/*! - * \fn QString ProductData::qbsFilePath() const - * \brief The qbs source file in which the product is defined. - */ - -/*! - * \fn int ProductData::qbsLine() const - * \brief The line in at which the product is defined in the source file. - */ - -/*! - * \fn QString ProductData::fileTags() const - * \brief The file tags of this product. Corresponds to a Product's "type" property in - * a qbs source file. - */ - -/*! - * \fn QVariantMap ProductData::properties() const - * \brief The set of properties valid in this product. - * Note that product properties can be overwritten in a Group. - * \sa GroupData::properties() - */ - -/*! - * \fn QList<GroupData> groups() const - * \brief The list of \c GroupData in this product. - */ - - -/*! - * \class ProjectData - * \brief The \c ProjectData class corresponds to the Project item in a qbs source file. - */ - -/*! - * \fn CodeLocation ProjectData::location() const - * \brief The qbs source file in which the project is defined. - */ - -/*! - * \fn QString ProjectData::buildDirectory() const - * \brief The base directory under which the build artifacts of this project will be created. - */ - -/*! - * \fn QList<ProductData> ProjectData::products() const - * \brief The products in this project. - */ - -/*! - * \fn bool ProductData::isEnabled() const - * \brief Returns true if this Product is enabled in Qbs. - * This method returns the "condition" property of the Product definition. If a product is - * enabled, then it will be built in the current configuration. - * \sa GroupData::isEnabled() - */ - } // namespace qbs diff --git a/src/lib/api/projectdata.h b/src/lib/api/projectdata.h index e16678a21..1097c5e24 100644 --- a/src/lib/api/projectdata.h +++ b/src/lib/api/projectdata.h @@ -32,6 +32,7 @@ #include "../tools/codelocation.h" #include "../tools/qbs_export.h" +#include <QExplicitlySharedDataPointer> #include <QList> #include <QPair> #include <QString> @@ -39,11 +40,13 @@ #include <QVariantMap> namespace qbs { -namespace Internal -{ +namespace Internal { +class GroupDataPrivate; +class ProductDataPrivate; class ProjectPrivate; +class ProjectDataPrivate; class PropertyMapPrivate; -} +} // namespace Internal class PropertyMap; @@ -78,31 +81,25 @@ private: Internal::PropertyMapPrivate *d; }; -// TODO: explicitly shared? - class QBS_EXPORT GroupData { friend class Internal::ProjectPrivate; public: GroupData(); - - CodeLocation location() const { return m_location; } - QString name() const { return m_name; } - QStringList filePaths() const { return m_filePaths; } - QStringList expandedWildcards() const { return m_expandedWildcards; } - PropertyMap properties() const { return m_properties; } - bool isEnabled() const { return m_isEnabled; } - - // TODO: Filter out double entries here or somewhere else? - QStringList allFilePaths() const { return filePaths() + expandedWildcards(); } + GroupData(const GroupData &other); + GroupData &operator=(const GroupData &other); + ~GroupData(); + + CodeLocation location() const; + QString name() const; + QStringList filePaths() const; + QStringList expandedWildcards() const; + PropertyMap properties() const; + bool isEnabled() const; + QStringList allFilePaths() const; private: - QString m_name; - CodeLocation m_location; - QStringList m_filePaths; - QStringList m_expandedWildcards; - PropertyMap m_properties; - bool m_isEnabled; + QExplicitlySharedDataPointer<Internal::GroupDataPrivate> d; }; QBS_EXPORT bool operator==(const GroupData &lhs, const GroupData &rhs); @@ -114,21 +111,19 @@ class QBS_EXPORT ProductData friend class Internal::ProjectPrivate; public: ProductData(); + ProductData(const ProductData &other); + ProductData &operator=(const ProductData &other); + ~ProductData(); - QString name() const { return m_name; } - CodeLocation location() const { return m_location; } - QStringList fileTags() const { return m_fileTags; } - PropertyMap properties() const { return m_properties; } - QList<GroupData> groups() const { return m_groups; } - bool isEnabled() const { return m_isEnabled; } + QString name() const; + CodeLocation location() const; + QStringList fileTags() const; + PropertyMap properties() const; + QList<GroupData> groups() const; + bool isEnabled() const; private: - QString m_name; - CodeLocation m_location; - QStringList m_fileTags; - PropertyMap m_properties; - QList<GroupData> m_groups; - bool m_isEnabled; + QExplicitlySharedDataPointer<Internal::ProductDataPrivate> d; }; QBS_EXPORT bool operator==(const ProductData &lhs, const ProductData &rhs); @@ -140,15 +135,16 @@ class QBS_EXPORT ProjectData friend class Internal::ProjectPrivate; public: ProjectData(); + ProjectData(const ProjectData &other); + ProjectData &operator=(const ProjectData &other); + ~ProjectData(); - CodeLocation location() const { return m_location; } - QString buildDirectory() const { return m_buildDir; } - QList<ProductData> products() const { return m_products; } + CodeLocation location() const; + QString buildDirectory() const; + QList<ProductData> products() const; private: - CodeLocation m_location; - QList<ProductData> m_products; - QString m_buildDir; + QExplicitlySharedDataPointer<Internal::ProjectDataPrivate> d; }; QBS_EXPORT bool operator==(const ProjectData &lhs, const ProjectData &rhs); diff --git a/src/lib/api/projectdata_p.h b/src/lib/api/projectdata_p.h new file mode 100644 index 000000000..c544dd9d9 --- /dev/null +++ b/src/lib/api/projectdata_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#ifndef QBS_PROJECTDATA_P_H +#define QBS_PROJECTDATA_P_H + +#include "projectdata.h" + +#include <QSharedData> + +namespace qbs { +namespace Internal { + +class GroupDataPrivate : public QSharedData +{ +public: + QString name; + CodeLocation location; + QStringList filePaths; + QStringList expandedWildcards; + PropertyMap properties; + bool isEnabled; +}; + +class ProductDataPrivate : public QSharedData +{ +public: + QString name; + CodeLocation location; + QStringList fileTags; + PropertyMap properties; + QList<GroupData> groups; + bool isEnabled; +}; + +class ProjectDataPrivate : public QSharedData +{ +public: + CodeLocation location; + QList<ProductData> products; + QString buildDir; +}; + +} // namespace Internal +} // namespace qbs + +#endif // Include guard. diff --git a/src/lib/buildgraph/artifactcleaner.cpp b/src/lib/buildgraph/artifactcleaner.cpp index 538685b69..33cef580a 100644 --- a/src/lib/buildgraph/artifactcleaner.cpp +++ b/src/lib/buildgraph/artifactcleaner.cpp @@ -107,12 +107,14 @@ private: { if (artifact->product != m_product) return; - if (artifact->parents.isEmpty() && m_options.cleanType == CleanOptions::CleanupTemporaries) + if (artifact->parents.isEmpty() + && m_options.cleanType() == CleanOptions::CleanupTemporaries) { return; + } try { - removeArtifactFromDisk(artifact, m_options.dryRun, m_logger); + removeArtifactFromDisk(artifact, m_options.dryRun(), m_logger); } catch (const Error &error) { - if (!m_options.keepGoing) + if (!m_options.keepGoing()) throw; m_logger.qbsWarning() << error.toString(); m_hasError = true; @@ -176,10 +178,10 @@ void ArtifactCleaner::removeEmptyDirectories(const QString &rootDir, const Clean subTreeIsEmpty = false; } if (subTreeIsEmpty) { - printRemovalMessage(rootDir, options.dryRun, m_logger); + printRemovalMessage(rootDir, options.dryRun(), m_logger); if (!QDir::root().rmdir(rootDir)) { Error error(Tr::tr("Failure to remove empty directory '%1'.").arg(rootDir)); - if (!options.keepGoing) + if (!options.keepGoing()) throw error; m_logger.qbsWarning() << error.toString(); m_hasError = true; diff --git a/src/lib/buildgraph/buildgraph.cpp b/src/lib/buildgraph/buildgraph.cpp index a9ddbf7d8..6e311bad3 100644 --- a/src/lib/buildgraph/buildgraph.cpp +++ b/src/lib/buildgraph/buildgraph.cpp @@ -191,8 +191,9 @@ void setupScriptEngineForProduct(ScriptEngine *engine, const ResolvedProductCons QVariant(reinterpret_cast<qulonglong>(product->project.data()))); QScriptValue projectScriptValue; projectScriptValue = engine->newObject(); - projectScriptValue.setProperty("filePath", product->project->location.fileName); - projectScriptValue.setProperty("path", FileInfo::path(product->project->location.fileName)); + projectScriptValue.setProperty("filePath", product->project->location.fileName()); + projectScriptValue.setProperty("path", + FileInfo::path(product->project->location.fileName())); const QVariantMap &projectProperties = product->project->projectProperties(); for (QVariantMap::const_iterator it = projectProperties.begin(); it != projectProperties.end(); ++it) @@ -463,8 +464,9 @@ BuildGraphLoader::LoadResult BuildGraphLoader::load(const SetupProjectParameters m_result = LoadResult(); m_evalContext = evalContext; - const QString projectId = ResolvedProject::deriveId(parameters.buildConfiguration); - const QString buildDir = ResolvedProject::deriveBuildDirectory(parameters.buildRoot, projectId); + const QString projectId = ResolvedProject::deriveId(parameters.buildConfiguration()); + const QString buildDir + = ResolvedProject::deriveBuildDirectory(parameters.buildRoot(), projectId); const QString buildGraphFilePath = ProjectBuildData::deriveBuildGraphFilePath(buildDir, projectId); @@ -472,7 +474,7 @@ BuildGraphLoader::LoadResult BuildGraphLoader::load(const SetupProjectParameters m_logger.qbsDebug() << "[BG] trying to load: " << buildGraphFilePath; if (!pool.load(buildGraphFilePath)) return m_result; - if (!isConfigCompatible(parameters.buildConfiguration, pool.headData().projectConfig)) { + if (!isConfigCompatible(parameters.buildConfiguration(), pool.headData().projectConfig)) { m_logger.qbsDebug() << "[BG] Cannot use stored build graph: " "Incompatible project configuration."; return m_result; @@ -496,12 +498,12 @@ BuildGraphLoader::LoadResult BuildGraphLoader::load(const SetupProjectParameters } } - if (QFileInfo(project->location.fileName) != QFileInfo(parameters.projectFilePath)) { + if (QFileInfo(project->location.fileName()) != QFileInfo(parameters.projectFilePath())) { QString errorMessage = Tr::tr("Stored build graph is for project file '%1', but " "input file is '%2'. ") - .arg(QDir::toNativeSeparators(project->location.fileName), - QDir::toNativeSeparators(parameters.projectFilePath)); - if (!parameters.ignoreDifferentProjectFilePath) { + .arg(QDir::toNativeSeparators(project->location.fileName()), + QDir::toNativeSeparators(parameters.projectFilePath())); + if (!parameters.ignoreDifferentProjectFilePath()) { errorMessage += Tr::tr("Aborting."); throw Error(errorMessage); } @@ -512,7 +514,7 @@ BuildGraphLoader::LoadResult BuildGraphLoader::load(const SetupProjectParameters } foreach (const ResolvedProductPtr &p, project->products) p->project = project; - project->location = CodeLocation(parameters.projectFilePath, 1, 1); + project->location = CodeLocation(parameters.projectFilePath(), 1, 1); project->setBuildConfiguration(pool.headData().projectConfig); project->buildDirectory = buildDir; m_result.loadedProject = project; @@ -526,7 +528,7 @@ void BuildGraphLoader::trackProjectChanges(const SetupProjectParameters ¶met { const FileInfo bgfi(buildGraphFilePath); const bool projectFileChanged - = bgfi.lastModified() < FileInfo(parameters.projectFilePath).lastModified(); + = bgfi.lastModified() < FileInfo(parameters.projectFilePath()).lastModified(); if (projectFileChanged) m_logger.qbsTrace() << "Project file changed, must re-resolve project."; @@ -541,7 +543,7 @@ void BuildGraphLoader::trackProjectChanges(const SetupProjectParameters ¶met bool referencedProductRemoved = false; QList<ResolvedProductPtr> changedProducts; foreach (const ResolvedProductPtr &product, restoredProject->products) { - const FileInfo pfi(product->location.fileName); + const FileInfo pfi(product->location.fileName()); if (!pfi.exists()) { referencedProductRemoved = true; } else if (bgfi.lastModified() < pfi.lastModified()) { @@ -569,7 +571,7 @@ void BuildGraphLoader::trackProjectChanges(const SetupProjectParameters ¶met } Loader ldr(m_evalContext->engine(), m_logger); - ldr.setSearchPaths(parameters.searchPaths); + ldr.setSearchPaths(parameters.searchPaths()); m_result.newlyResolvedProject = ldr.loadProject(parameters); QMap<QString, ResolvedProductPtr> freshProductsByName; diff --git a/src/lib/buildgraph/executor.cpp b/src/lib/buildgraph/executor.cpp index b2990ce14..b34d52275 100644 --- a/src/lib/buildgraph/executor.cpp +++ b/src/lib/buildgraph/executor.cpp @@ -168,10 +168,10 @@ void Executor::setProducts(const QList<ResolvedProductPtr> &productsToBuild) void Executor::doBuild() { - if (m_buildOptions.maxJobCount <= 0) { - m_buildOptions.maxJobCount = BuildOptions::defaultMaxJobCount(); + if (m_buildOptions.maxJobCount() <= 0) { + m_buildOptions.setMaxJobCount(BuildOptions::defaultMaxJobCount()); m_logger.qbsDebug() << "max job count not explicitly set, using value of " - << m_buildOptions.maxJobCount; + << m_buildOptions.maxJobCount(); } QBS_CHECK(m_state == ExecutorIdle); m_leaves.clear(); @@ -194,17 +194,17 @@ void Executor::doBuild() } m_logger.qbsDebug() << QString::fromLocal8Bit("[EXEC] preparing executor for %1 jobs " - "in parallel").arg(m_buildOptions.maxJobCount); - addExecutorJobs(m_buildOptions.maxJobCount); + "in parallel").arg(m_buildOptions.maxJobCount()); + addExecutorJobs(m_buildOptions.maxJobCount()); foreach (ExecutorJob * const job, m_availableJobs) - job->setDryRun(m_buildOptions.dryRun); + job->setDryRun(m_buildOptions.dryRun()); initializeArtifactsState(); - Artifact::BuildState initialBuildState = m_buildOptions.changedFiles.isEmpty() + Artifact::BuildState initialBuildState = m_buildOptions.changedFiles().isEmpty() ? Artifact::Buildable : Artifact::Built; QList<Artifact *> changedArtifacts; - foreach (const QString &filePath, m_buildOptions.changedFiles) { + foreach (const QString &filePath, m_buildOptions.changedFiles()) { QList<Artifact *> artifacts; artifacts.append(m_project->buildData->lookupArtifacts(filePath)); if (artifacts.isEmpty()) { @@ -420,7 +420,7 @@ void Executor::buildArtifact(Artifact *artifact) } // create the output directories - if (!m_buildOptions.dryRun) { + if (!m_buildOptions.dryRun()) { ArtifactList::const_iterator it = artifact->transformer->outputs.begin(); for (; it != artifact->transformer->outputs.end(); ++it) { Artifact *output = *it; @@ -486,7 +486,7 @@ void Executor::finishJob(ExecutorJob *job, bool success) m_processingJobs.erase(it); m_availableJobs.append(job); - if (!success && !m_buildOptions.keepGoing) + if (!success && !m_buildOptions.keepGoing()) cancelJobs(); if (m_state == ExecutorRunning && m_progressObserver && m_progressObserver->canceled()) { @@ -683,7 +683,7 @@ void Executor::runAutoMoc() void Executor::onProcessError(const qbs::Error &err) { try { - if (m_buildOptions.keepGoing) { + if (m_buildOptions.keepGoing()) { Error fullWarning(err); fullWarning.prepend(Tr::tr("Ignoring the following errors on user request:")); emit reportWarning(fullWarning); diff --git a/src/lib/buildgraph/jscommandexecutor.cpp b/src/lib/buildgraph/jscommandexecutor.cpp index 8d07424db..9a2cbfa4a 100644 --- a/src/lib/buildgraph/jscommandexecutor.cpp +++ b/src/lib/buildgraph/jscommandexecutor.cpp @@ -105,8 +105,10 @@ public: if (scriptEngine->hasUncaughtException()) { result.success = false; result.errorMessage = scriptEngine->uncaughtException().toString(); - result.errorLocation = m_jsCommand->codeLocation(); - result.errorLocation.line += scriptEngine->uncaughtExceptionLineNumber(); + const CodeLocation &origLocation = m_jsCommand->codeLocation(); + result.errorLocation = CodeLocation(origLocation.fileName(), + origLocation.line() + scriptEngine->uncaughtExceptionLineNumber(), + origLocation.column()); } scriptEngine->popContext(); scriptEngine->clearExceptions(); diff --git a/src/lib/buildgraph/processcommandexecutor.cpp b/src/lib/buildgraph/processcommandexecutor.cpp index 533feda26..a7f01270b 100644 --- a/src/lib/buildgraph/processcommandexecutor.cpp +++ b/src/lib/buildgraph/processcommandexecutor.cpp @@ -40,6 +40,7 @@ #include <tools/fileinfo.h> #include <tools/hostosinfo.h> #include <tools/processresult.h> +#include <tools/processresult_p.h> #include <tools/qbsassert.h> #include <QDir> @@ -192,28 +193,28 @@ QString ProcessCommandExecutor::filterProcessOutput(const QByteArray &_output, void ProcessCommandExecutor::sendProcessOutput(bool success) { ProcessResult result; - result.binary = m_program; - result.arguments = m_arguments; - result.workingDirectory = m_process.workingDirectory(); - if (result.workingDirectory.isEmpty()) - result.workingDirectory = QDir::currentPath(); - result.exitCode = m_process.exitCode(); - result.exitStatus = m_process.exitStatus(); - result.success = success; + result.d->executableFilePath = m_program; + result.d->arguments = m_arguments; + result.d->workingDirectory = m_process.workingDirectory(); + if (result.workingDirectory().isEmpty()) + result.d->workingDirectory = QDir::currentPath(); + result.d->exitCode = m_process.exitCode(); + result.d->exitStatus = m_process.exitStatus(); + result.d->success = success; QString tmp = filterProcessOutput(m_process.readAllStandardOutput(), processCommand()->stdoutFilterFunction()); if (!tmp.isEmpty()) { if (tmp.endsWith(QLatin1Char('\n'))) tmp.chop(1); - result.stdOut = tmp.split(QLatin1Char('\n')); + result.d->stdOut = tmp.split(QLatin1Char('\n')); } tmp = filterProcessOutput(m_process.readAllStandardError(), processCommand()->stderrFilterFunction()); if (!tmp.isEmpty()) { if (tmp.endsWith(QLatin1Char('\n'))) tmp.chop(1); - result.stdErr = tmp.split(QLatin1Char('\n')); + result.d->stdErr = tmp.split(QLatin1Char('\n')); } emit reportProcessResult(result); diff --git a/src/lib/buildgraph/productinstaller.cpp b/src/lib/buildgraph/productinstaller.cpp index 81d40f4c9..70031716b 100644 --- a/src/lib/buildgraph/productinstaller.cpp +++ b/src/lib/buildgraph/productinstaller.cpp @@ -48,10 +48,10 @@ ProductInstaller::ProductInstaller(const QList<ResolvedProductPtr> &products, const InstallOptions &options, ProgressObserver *observer, const Logger &logger) : m_products(products), m_options(options), m_observer(observer), m_logger(logger) { - if (!m_options.installRoot.isEmpty()) { - QFileInfo installRootFileInfo(m_options.installRoot); + if (!m_options.installRoot().isEmpty()) { + QFileInfo installRootFileInfo(m_options.installRoot()); QBS_ASSERT(installRootFileInfo.isAbsolute(), /* just complain */); - if (m_options.removeFirst) { + if (m_options.removeExistingInstallation()) { const QString cfp = installRootFileInfo.canonicalFilePath(); if (cfp == QFileInfo(QDir::rootPath()).canonicalFilePath()) throw Error(Tr::tr("Refusing to remove root directory.")); @@ -65,19 +65,19 @@ ProductInstaller::ProductInstaller(const QList<ResolvedProductPtr> &products, throw Error(Tr::tr("Cannot deduce install root, because there are no products.")); const ResolvedProductConstPtr &product = m_products.first(); - m_options.installRoot - = product->properties->qbsPropertyValue(QLatin1String("sysroot")).toString(); - if (m_options.installRoot.isEmpty()) { - m_options.installRoot = product->project->buildDirectory - + QLatin1Char('/') + InstallOptions::defaultInstallRoot(); - } else if (m_options.removeFirst) { + m_options.setInstallRoot(product->properties + ->qbsPropertyValue(QLatin1String("sysroot")).toString()); + if (m_options.installRoot().isEmpty()) { + m_options.setInstallRoot(product->project->buildDirectory + + QLatin1Char('/') + InstallOptions::defaultInstallRoot()); + } else if (m_options.removeExistingInstallation()) { throw Error(Tr::tr("Refusing to remove sysroot.")); } } void ProductInstaller::install() { - if (m_options.removeFirst) + if (m_options.removeExistingInstallation()) removeInstallRoot(); QList<const Artifact *> artifactsToInstall; @@ -98,8 +98,8 @@ void ProductInstaller::install() void ProductInstaller::removeInstallRoot() { - const QString nativeInstallRoot = QDir::toNativeSeparators(m_options.installRoot); - if (m_options.dryRun) { + const QString nativeInstallRoot = QDir::toNativeSeparators(m_options.installRoot()); + if (m_options.dryRun()) { m_logger.qbsInfo() << Tr::tr("Would remove install root '%1'.").arg(nativeInstallRoot); return; } @@ -107,9 +107,9 @@ void ProductInstaller::removeInstallRoot() .arg(nativeInstallRoot); QString errorMessage; - if (!removeDirectoryWithContents(m_options.installRoot, &errorMessage)) { + if (!removeDirectoryWithContents(m_options.installRoot(), &errorMessage)) { const QString fullErrorMessage = Tr::tr("Cannot remove install root '%1': %2") - .arg(QDir::toNativeSeparators(m_options.installRoot), errorMessage); + .arg(QDir::toNativeSeparators(m_options.installRoot()), errorMessage); handleError(fullErrorMessage); } } @@ -120,12 +120,12 @@ void ProductInstaller::copyFile(const Artifact *artifact) throw Error(Tr::tr("Installation canceled due to user request.")); const QString relativeInstallDir = artifact->properties->qbsPropertyValue(QLatin1String("installDir")).toString(); - QString targetDir = m_options.installRoot; + QString targetDir = m_options.installRoot(); targetDir.append(QLatin1Char('/')).append(relativeInstallDir); targetDir = QDir::cleanPath(targetDir); const QString nativeFilePath = QDir::toNativeSeparators(artifact->filePath()); const QString nativeTargetDir = QDir::toNativeSeparators(targetDir); - if (m_options.dryRun) { + if (m_options.dryRun()) { m_logger.qbsInfo() << Tr::tr("Would copy file '%1' into target directory '%2'.") .arg(nativeFilePath, nativeTargetDir); return; @@ -146,7 +146,7 @@ void ProductInstaller::copyFile(const Artifact *artifact) void ProductInstaller::handleError(const QString &message) { - if (!m_options.keepGoing) + if (!m_options.keepGoing()) throw Error(message); m_logger.qbsWarning() << message; } diff --git a/src/lib/buildgraph/projectbuilddata.cpp b/src/lib/buildgraph/projectbuilddata.cpp index 3bd8843b4..ed46a088e 100644 --- a/src/lib/buildgraph/projectbuilddata.cpp +++ b/src/lib/buildgraph/projectbuilddata.cpp @@ -291,11 +291,11 @@ void BuildDataResolver::resolveProductBuildData(const ResolvedProductPtr &produc } //add qbsFile artifact - Artifact *qbsFileArtifact = lookupArtifact(product, product->location.fileName); + Artifact *qbsFileArtifact = lookupArtifact(product, product->location.fileName()); if (!qbsFileArtifact) { qbsFileArtifact = new Artifact(m_project); qbsFileArtifact->artifactType = Artifact::SourceFile; - qbsFileArtifact->setFilePath(product->location.fileName); + qbsFileArtifact->setFilePath(product->location.fileName()); qbsFileArtifact->properties = product->properties; insertArtifact(product, qbsFileArtifact, m_logger); } diff --git a/src/lib/buildgraph/rulesapplicator.cpp b/src/lib/buildgraph/rulesapplicator.cpp index a9781d10e..b5ec6ffde 100644 --- a/src/lib/buildgraph/rulesapplicator.cpp +++ b/src/lib/buildgraph/rulesapplicator.cpp @@ -245,15 +245,15 @@ Artifact *RulesApplicator::createOutputArtifact(const RuleArtifactConstPtr &rule + "] -> [" + outputArtifact->fileTags.toStringList().join(", ") + "]"; e += QString(" while trying to apply: %1:%2:%3 %4\n") - .arg(m_rule->script->location.fileName) - .arg(m_rule->script->location.line) - .arg(m_rule->script->location.column) + .arg(m_rule->script->location.fileName()) + .arg(m_rule->script->location.line()) + .arg(m_rule->script->location.column()) .arg(th); e += QString(" was already defined in: %1:%2:%3 %4\n") - .arg(outputArtifact->transformer->rule->script->location.fileName) - .arg(outputArtifact->transformer->rule->script->location.line) - .arg(outputArtifact->transformer->rule->script->location.column) + .arg(outputArtifact->transformer->rule->script->location.fileName()) + .arg(outputArtifact->transformer->rule->script->location.line()) + .arg(outputArtifact->transformer->rule->script->location.column()) .arg(th); throw Error(e); } diff --git a/src/lib/buildgraph/transformer.cpp b/src/lib/buildgraph/transformer.cpp index 5a8ff76a1..27ee4af5d 100644 --- a/src/lib/buildgraph/transformer.cpp +++ b/src/lib/buildgraph/transformer.cpp @@ -146,8 +146,8 @@ void Transformer::createCommands(const PrepareScriptConstPtr &script, modulePropertiesUsedInPrepareScript = engine->properties(); if (Q_UNLIKELY(engine->hasUncaughtException())) throw Error("evaluating prepare script: " + engine->uncaughtException().toString(), - CodeLocation(script->location.fileName, - script->location.line + engine->uncaughtExceptionLineNumber() - 1)); + CodeLocation(script->location.fileName(), + script->location.line() + engine->uncaughtExceptionLineNumber() - 1)); qDeleteAll(commands); commands.clear(); diff --git a/src/lib/language/language.cpp b/src/lib/language/language.cpp index 86962b0eb..1fe2ababb 100644 --- a/src/lib/language/language.cpp +++ b/src/lib/language/language.cpp @@ -629,9 +629,12 @@ ResolvedProject::~ResolvedProject() void ResolvedProject::load(PersistentPool &pool) { - location.fileName = pool.idLoadString(); - pool.stream() >> location.line; - pool.stream() >> location.column; + const QString fileName = pool.idLoadString(); + int line; + int column; + pool.stream() >> line; + pool.stream() >> column; + location = CodeLocation(fileName, line, column); pool.stream() >> m_id; pool.stream() >> platformEnvironment; @@ -655,9 +658,9 @@ void ResolvedProject::load(PersistentPool &pool) void ResolvedProject::store(PersistentPool &pool) const { - pool.storeString(location.fileName); - pool.stream() << location.line; - pool.stream() << location.column; + pool.storeString(location.fileName()); + pool.stream() << location.line(); + pool.stream() << location.column(); pool.stream() << m_id; pool.stream() << platformEnvironment; diff --git a/src/lib/language/loader.cpp b/src/lib/language/loader.cpp index 54c670590..73e397ae2 100644 --- a/src/lib/language/loader.cpp +++ b/src/lib/language/loader.cpp @@ -84,7 +84,7 @@ void Loader::setSearchPaths(const QStringList &_searchPaths) ResolvedProjectPtr Loader::loadProject(const SetupProjectParameters ¶meters) { - QBS_CHECK(QFileInfo(parameters.projectFilePath).isAbsolute()); + QBS_CHECK(QFileInfo(parameters.projectFilePath()).isAbsolute()); // 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 @@ -92,15 +92,14 @@ ResolvedProjectPtr Loader::loadProject(const SetupProjectParameters ¶meters) // we have enough information. if (m_progressObserver) { m_progressObserver->initialize(Tr::tr("Resolving project for configuration %1") - .arg(ResolvedProject::deriveId(parameters.buildConfiguration)), 1); + .arg(ResolvedProject::deriveId(parameters.buildConfiguration())), 1); } ModuleLoaderResult loadResult - = m_moduleLoader->load(parameters.projectFilePath, - parameters.buildConfiguration, + = m_moduleLoader->load(parameters.projectFilePath(), + parameters.buildConfiguration(), true); - ResolvedProjectPtr project = m_projectResolver->resolve(loadResult, parameters.buildRoot, - parameters.buildConfiguration); - return project; + return m_projectResolver->resolve(loadResult, parameters.buildRoot(), + parameters.buildConfiguration()); } QByteArray Loader::qmlTypeInfo() diff --git a/src/lib/language/tst_language.cpp b/src/lib/language/tst_language.cpp index 9b82ea70e..ec825f86a 100644 --- a/src/lib/language/tst_language.cpp +++ b/src/lib/language/tst_language.cpp @@ -57,7 +57,7 @@ TestLanguage::TestLanguage(ILogSink *logSink) { qsrand(QTime::currentTime().msec()); qRegisterMetaType<QList<bool> >("QList<bool>"); - defaultParameters.buildRoot = "/some/build/directory"; + defaultParameters.setBuildRoot("/some/build/directory"); } TestLanguage::~TestLanguage() @@ -95,7 +95,7 @@ void TestLanguage::handleInitCleanupDataTags(const char *projectFileName, bool * *handled = true; bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject(projectFileName); + defaultParameters.setProjectFilePath(testProject(projectFileName)); project = loader->loadProject(defaultParameters); QVERIFY(project); } catch (const Error &e) { @@ -126,8 +126,9 @@ void TestLanguage::initTestCase() loader = new Loader(m_engine, m_logger); loader->setSearchPaths(QStringList() << QLatin1String(SRCDIR "/../../share/qbs")); - setConfigProperty(defaultParameters.buildConfiguration, - QStringList() << "qbs" << "targetOS", "linux"); + QVariantMap buildConfig = defaultParameters.buildConfiguration(); + setConfigProperty(buildConfig, QStringList() << "qbs" << "targetOS", "linux"); + defaultParameters.setBuildConfiguration(buildConfig); QVERIFY(QFileInfo(m_wildcardsTestDirPath).isAbsolute()); } @@ -140,7 +141,7 @@ void TestLanguage::baseProperty() { bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("baseproperty.qbs"); + defaultParameters.setProjectFilePath(testProject("baseproperty.qbs")); project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -162,7 +163,7 @@ void TestLanguage::conditionalDepends() ResolvedProductPtr product; ResolvedModuleConstPtr dependency; try { - defaultParameters.projectFilePath = testProject("conditionaldepends.qbs"); + defaultParameters.setProjectFilePath(testProject("conditionaldepends.qbs")); project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -238,7 +239,7 @@ void TestLanguage::environmentVariable() try { const QByteArray productName = QByteArray("MyApp") + QByteArray::number(qrand()); qputenv("PRODUCT_NAME", productName); - defaultParameters.projectFilePath = testProject("environmentvariable.qbs"); + defaultParameters.setProjectFilePath(testProject("environmentvariable.qbs")); project = loader->loadProject(defaultParameters); qputenv("PRODUCT_NAME", QByteArray()); QVERIFY(project); @@ -272,7 +273,7 @@ void TestLanguage::erroneousFiles() QFETCH(QString, errorMessage); QString fileName = QString::fromLocal8Bit(QTest::currentDataTag()) + QLatin1String(".qbs"); try { - defaultParameters.projectFilePath = testProject("/erroneous/") + fileName; + defaultParameters.setProjectFilePath(testProject("/erroneous/") + fileName); loader->loadProject(defaultParameters); } catch (const Error &e) { if (!e.toString().contains(errorMessage)) { @@ -289,7 +290,7 @@ void TestLanguage::exports() { bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("exports.qbs"); + defaultParameters.setProjectFilePath(testProject("exports.qbs")); ResolvedProjectPtr project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -345,15 +346,15 @@ void TestLanguage::fileContextProperties() { bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("filecontextproperties.qbs"); + defaultParameters.setProjectFilePath(testProject("filecontextproperties.qbs")); project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); QVERIFY(product); QVariantMap cfg = product->properties->value(); - QCOMPARE(cfg.value("narf").toString(), defaultParameters.projectFilePath); - QString dirPath = QFileInfo(defaultParameters.projectFilePath).absolutePath(); + QCOMPARE(cfg.value("narf").toString(), defaultParameters.projectFilePath()); + QString dirPath = QFileInfo(defaultParameters.projectFilePath()).absolutePath(); QCOMPARE(cfg.value("zort").toString(), dirPath); } catch (const Error &e) { exceptionCaught = true; @@ -406,7 +407,7 @@ void TestLanguage::groupName() { bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("groupname.qbs"); + defaultParameters.setProjectFilePath(testProject("groupname.qbs")); ResolvedProjectPtr project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -516,7 +517,7 @@ void TestLanguage::idUsage() { bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("idusage.qbs"); + defaultParameters.setProjectFilePath(testProject("idusage.qbs")); ResolvedProjectPtr project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -608,12 +609,12 @@ void TestLanguage::jsImportUsedInMultipleScopes() bool exceptionCaught = false; try { - QVariantMap customBuildConfig = defaultParameters.buildConfiguration; + QVariantMap customBuildConfig = defaultParameters.buildConfiguration(); setConfigProperty(customBuildConfig, QStringList() << "qbs" << "buildVariant", buildVariant); SetupProjectParameters params = defaultParameters; - params.projectFilePath = testProject("jsimportsinmultiplescopes.qbs"); - params.buildConfiguration = customBuildConfig; + params.setProjectFilePath(testProject("jsimportsinmultiplescopes.qbs")); + params.setBuildConfiguration(customBuildConfig); ResolvedProjectPtr project = loader->loadProject(params); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -682,7 +683,7 @@ void TestLanguage::moduleScope() bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("modulescope.qbs"); + defaultParameters.setProjectFilePath(testProject("modulescope.qbs")); ResolvedProjectPtr project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -754,7 +755,7 @@ void TestLanguage::outerInGroup() { bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("outerInGroup.qbs"); + defaultParameters.setProjectFilePath(testProject("outerInGroup.qbs")); ResolvedProjectPtr project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -788,14 +789,14 @@ void TestLanguage::pathProperties() { bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("pathproperties.qbs"); + defaultParameters.setProjectFilePath(testProject("pathproperties.qbs")); project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); ResolvedProductPtr product = products.value("product1"); QVERIFY(product); QVariantMap cfg = product->properties->value(); - QString projectFileDir = QFileInfo(defaultParameters.projectFilePath).absolutePath(); + QString projectFileDir = QFileInfo(defaultParameters.projectFilePath()).absolutePath(); QCOMPARE(cfg.value("projectFileDir").toString(), projectFileDir); QStringList filesInProjectFileDir = QStringList() << FileInfo::resolvePath(projectFileDir, "aboutdialog.h") @@ -819,7 +820,7 @@ void TestLanguage::productConditions() { bool exceptionCaught = false; try { - defaultParameters.projectFilePath = testProject("productconditions.qbs"); + defaultParameters.setProjectFilePath(testProject("productconditions.qbs")); ResolvedProjectPtr project = loader->loadProject(defaultParameters); QVERIFY(project); QHash<QString, ResolvedProductPtr> products = productsFromProject(project); @@ -1106,7 +1107,7 @@ void TestLanguage::wildcards() bool exceptionCaught = false; ResolvedProductPtr product; try { - defaultParameters.projectFilePath = projectFilePath; + defaultParameters.setProjectFilePath(projectFilePath); project = loader->loadProject(defaultParameters); QVERIFY(project); const QHash<QString, ResolvedProductPtr> products = productsFromProject(project); diff --git a/src/lib/lib.qbs b/src/lib/lib.qbs index 39f097853..e5478858b 100644 --- a/src/lib/lib.qbs +++ b/src/lib/lib.qbs @@ -41,6 +41,7 @@ DynamicLibrary { "jobs.cpp", "project.cpp", "projectdata.cpp", + "projectdata_p.h", "propertymap_p.h", "runenvironment.cpp", ] @@ -250,6 +251,8 @@ DynamicLibrary { "persistence.h", "persistentobject.h", "preferences.cpp", + "processresult.cpp", + "processresult_p.h", "profile.cpp", "progressobserver.cpp", "progressobserver.h", diff --git a/src/lib/logging/ilogsink.cpp b/src/lib/logging/ilogsink.cpp index a9da808d8..0e8cc7f7a 100644 --- a/src/lib/logging/ilogsink.cpp +++ b/src/lib/logging/ilogsink.cpp @@ -29,7 +29,7 @@ #include "ilogsink.h" #include <QByteArray> -#include <QString> +#include <QMutex> namespace qbs { @@ -62,17 +62,40 @@ QString logLevelName(LoggerLevel level) return QString(); } +class ILogSink::ILogSinkPrivate +{ +public: + LoggerLevel logLevel; + QMutex mutex; +}; + +ILogSink::ILogSink() : d(new ILogSinkPrivate) +{ + d->logLevel = defaultLogLevel(); +} + ILogSink::~ILogSink() { + delete d; +} + +void ILogSink::setLogLevel(LoggerLevel level) +{ + d->logLevel = level; +} + +LoggerLevel ILogSink::logLevel() const +{ + return d->logLevel; } void ILogSink::printMessage(LoggerLevel level, const QString &message, const QString &tag, bool force) { if (force || willPrint(level)) { - m_mutex.lock(); + d->mutex.lock(); doPrintMessage(level, message, tag); - m_mutex.unlock(); + d->mutex.unlock(); } } diff --git a/src/lib/logging/ilogsink.h b/src/lib/logging/ilogsink.h index dfaeeea3a..abb34aee7 100644 --- a/src/lib/logging/ilogsink.h +++ b/src/lib/logging/ilogsink.h @@ -31,8 +31,6 @@ #include "../tools/qbs_export.h" -#include <QtGlobal> -#include <QMutex> #include <QString> namespace qbs { @@ -56,11 +54,11 @@ class QBS_EXPORT ILogSink { Q_DISABLE_COPY(ILogSink) public: - ILogSink() : m_logLevel(defaultLogLevel()) {} + ILogSink(); virtual ~ILogSink(); - void setLogLevel(LoggerLevel level) { m_logLevel = level; } - LoggerLevel logLevel() const { return m_logLevel; } + void setLogLevel(LoggerLevel level); + LoggerLevel logLevel() const; bool willPrint(LoggerLevel level) const { return level <= logLevel(); } @@ -71,8 +69,8 @@ private: virtual void doPrintMessage(LoggerLevel level, const QString &message, const QString &tag) = 0; - LoggerLevel m_logLevel; - QMutex m_mutex; + class ILogSinkPrivate; + ILogSinkPrivate * const d; }; } // namespace qbs diff --git a/src/lib/tools/buildoptions.cpp b/src/lib/tools/buildoptions.cpp index b9d2608ea..945302e83 100644 --- a/src/lib/tools/buildoptions.cpp +++ b/src/lib/tools/buildoptions.cpp @@ -28,9 +28,27 @@ ****************************************************************************/ #include "buildoptions.h" +#include <QSharedData> #include <QThread> namespace qbs { +namespace Internal { + +class BuildOptionsPrivate : public QSharedData +{ +public: + BuildOptionsPrivate() : maxJobCount(0), dryRun(false), keepGoing(false), logElapsedTime(false) + { + } + + QStringList changedFiles; + int maxJobCount; + bool dryRun; + bool keepGoing; + bool logElapsedTime; +}; + +} // namespace Internal /*! * \class BuildOptions @@ -41,12 +59,40 @@ namespace qbs { /*! * \brief Creates a \c BuildOptions object and initializes its members to sensible default values. */ -BuildOptions::BuildOptions() - : maxJobCount(0) - , dryRun(false) - , keepGoing(false) - , logElapsedTime(false) +BuildOptions::BuildOptions() : d(new Internal::BuildOptionsPrivate) +{ +} + +BuildOptions::BuildOptions(const BuildOptions &other) : d(other.d) +{ +} + +BuildOptions &BuildOptions::operator=(const BuildOptions &other) +{ + d = other.d; + return *this; +} + +BuildOptions::~BuildOptions() +{ +} + +/*! + * \brief If non-empty, qbs pretends that only these files have changed. + * By default, this list is empty. + */ +QStringList BuildOptions::changedFiles() const +{ + return d->changedFiles; +} + +/*! + * \brief If the given list is empty, qbs will pretend only the listed files are changed. + * \note The list elements must be absolute file paths. + */ +void BuildOptions::setChangedFiles(const QStringList &changedFiles) { + d->changedFiles = changedFiles; } /*! @@ -59,45 +105,95 @@ int BuildOptions::defaultMaxJobCount() } /*! - * \variable BuildOptions::changedFiles - * \brief if non-empty, makes qbs pretend that only these files have changed + * \brief Returns the maximum number of build commands to run concurrently. + * If the value is not valid (i.e. <= 0), a sensible one will be derived at build time + * from the number of available processor cores at build time. + * The default is 0. + * \sa BuildOptions::defaultMaxJobCount */ +int BuildOptions::maxJobCount() const +{ + return d->maxJobCount; +} - /*! - * \variable BuildOptions::dryRun - * \brief if true, qbs will not actually execute any commands, but just show what would happen - * Note that the next call to build() on the same \c Project object will do nothing, since the - * internal state needs to be updated the same way as if an actual build has happened. You'll - * need to create a new \c Project object to do a real build. - */ +/*! + * \brief Controls how many build commands can be run in parallel. + * A value <= 0 leaves the decision to qbs. + */ +void BuildOptions::setMaxJobCount(int jobCount) +{ + d->maxJobCount = jobCount; +} + +/*! + * \brief Returns true iff qbs will not actually execute any commands, but just show what + * would happen. + * The default is false. + */ +bool BuildOptions::dryRun() const +{ + return d->dryRun; +} + +/*! + * \brief Controls whether qbs will actually build something. + * If the argument is true, qbs will just emit information about what it would do. Otherwise, + * the build is actually done. + * \note After you build with this setting enabled, the next call to \c build() on the same + * \c Project object will do nothing, since the internal state needs to be updated the same way + * as if an actual build had happened. You'll need to create a new \c Project object to do + * a real build afterwards. + */ +void BuildOptions::setDryRun(bool dryRun) +{ + d->dryRun = dryRun; +} /*! - * \variable BuildOptions::keepGoing - * \brief if true, do not abort on errors if possible + * \brief Returns true iff a build will continue after an error. * E.g. a failed compile command will result in a warning message being printed, instead of * stopping the build process right away. However, there might still be fatal errors after which the * build process cannot continue. + * The default is \c false. */ +bool BuildOptions::keepGoing() const +{ + return d->keepGoing; +} - /*! - * \variable - * \brief the maximum number of build commands to run concurrently - * If the value is not valid (i.e. <= 0), a sensible one will be derived from the number of - * available processor cores at build time. - */ +/*! + * \brief Controls whether a qbs will try to continue building after an error has occurred. + */ +void BuildOptions::setKeepGoing(bool keepGoing) +{ + d->keepGoing = keepGoing; +} + +/*! + * \brief Returns true iff the time the operation takes will be logged. + * The default is \c false. + */ +bool BuildOptions::logElapsedTime() const +{ + return d->logElapsedTime; +} + +/*! + * \brief Controls whether the build time will be measured and logged. + */ +void BuildOptions::setLogElapsedTime(bool log) +{ + d->logElapsedTime = log; +} - /*! - * \variable BuildOptions::logElapsedTime - * \brief true iff the time the operation takes should be logged - */ bool operator==(const BuildOptions &bo1, const BuildOptions &bo2) { - return bo1.changedFiles == bo2.changedFiles - && bo1.dryRun == bo2.dryRun - && bo1.keepGoing == bo2.keepGoing - && bo1.logElapsedTime == bo2.logElapsedTime - && bo1.maxJobCount == bo2.maxJobCount; + return bo1.changedFiles() == bo2.changedFiles() + && bo1.dryRun() == bo2.dryRun() + && bo1.keepGoing() == bo2.keepGoing() + && bo1.logElapsedTime() == bo2.logElapsedTime() + && bo1.maxJobCount() == bo2.maxJobCount(); } } // namespace qbs diff --git a/src/lib/tools/buildoptions.h b/src/lib/tools/buildoptions.h index e0b806a6a..0f40abb9e 100644 --- a/src/lib/tools/buildoptions.h +++ b/src/lib/tools/buildoptions.h @@ -31,22 +31,38 @@ #include "qbs_export.h" +#include <QSharedDataPointer> #include <QStringList> namespace qbs { +namespace Internal { class BuildOptionsPrivate; } class QBS_EXPORT BuildOptions { public: BuildOptions(); + BuildOptions(const BuildOptions &other); + BuildOptions &operator=(const BuildOptions &other); + ~BuildOptions(); + + QStringList changedFiles() const; + void setChangedFiles(const QStringList &changedFiles); static int defaultMaxJobCount(); + int maxJobCount() const; + void setMaxJobCount(int jobCount); + + bool dryRun() const; + void setDryRun(bool dryRun); + + bool keepGoing() const; + void setKeepGoing(bool keepGoing); + + bool logElapsedTime() const; + void setLogElapsedTime(bool log); - QStringList changedFiles; - int maxJobCount; - bool dryRun; - bool keepGoing; - bool logElapsedTime; +private: + QSharedDataPointer<Internal::BuildOptionsPrivate> d; }; bool operator==(const BuildOptions &bo1, const BuildOptions &bo2); diff --git a/src/lib/tools/cleanoptions.cpp b/src/lib/tools/cleanoptions.cpp index 0842b61e1..aa3279dd8 100644 --- a/src/lib/tools/cleanoptions.cpp +++ b/src/lib/tools/cleanoptions.cpp @@ -28,7 +28,23 @@ ****************************************************************************/ #include "cleanoptions.h" +#include <QSharedData> + namespace qbs { +namespace Internal { + +class CleanOptionsPrivate : public QSharedData +{ +public: + CleanOptionsPrivate() : cleanType(CleanOptions::CleanupAll), dryRun(false), keepGoing(false) {} + + CleanOptions::CleanType cleanType; + bool dryRun; + bool keepGoing; + bool logElapsedTime; +}; + +} /*! * \class CleanOptions @@ -36,19 +52,6 @@ namespace qbs { * cleaning operations. */ - /*! - * \variable CleanOptions::dryRun - * \brief if true, qbs will not actually remove any files, but just show what would happen. - */ - -/*! - * \variable CleanOptions::keepGoing - * \brief if true, do not abort on errors - * If a file cannot be removed, e.g. due to a permission problem, a warning will be printed and - * cleaning will continue. If this flag is not set, then the operation will abort - * immediately in case of an error. - */ - /*! * \enum CleanOptions::CleanType * This enum type specifies which kind of build artifacts to remove. @@ -58,18 +61,95 @@ namespace qbs { * would be left on the disk, but the .o files would be removed. */ +CleanOptions::CleanOptions() : d(new Internal::CleanOptionsPrivate) +{ +} + +CleanOptions::CleanOptions(const CleanOptions &other) : d(other.d) +{ +} + +CleanOptions &CleanOptions::operator=(const CleanOptions &other) +{ + d = other.d; + return *this; +} + +CleanOptions::~CleanOptions() +{ +} + /*! - * \variable CleanOptions::cleanType - * \brief what to remove + * \brief Returns information about which type of artifacts will be removed. */ +CleanOptions::CleanType CleanOptions::cleanType() const +{ + return d->cleanType; +} - /*! - * \variable CleanOptions::logElapsedTime - * \brief true iff the time the operation takes should be logged - */ +/*! + * \brief Controls which kind of artifacts to remove. + * \sa CleanOptions::CleanType + */ +void CleanOptions::setCleanType(CleanOptions::CleanType cleanType) +{ + d->cleanType = cleanType; +} -CleanOptions::CleanOptions() : cleanType(CleanupAll), dryRun(false), keepGoing(false) +/*! + * \brief Returns true iff qbs will not actually remove any files, but just show what would happen. + * The default is false. + */ +bool CleanOptions::dryRun() const +{ + return d->dryRun; +} + +/*! + * \brief Controls whether clean-up will actually take place. + * If the argument is true, then qbs will emit information about which files would be removed + * instead of actually doing it. + */ +void CleanOptions::setDryRun(bool dryRun) +{ + d->dryRun = dryRun; +} + +/*! + * Returns true iff clean-up will continue if an error occurs. + * The default is false. + */ +bool CleanOptions::keepGoing() const +{ + return d->dryRun; +} + +/*! + * \brief Controls whether to abort on errors. + * If the argument is true, then if a file cannot be removed e.g. due to a permission problem, + * a warning will be printed and the clean-up will continue. If the argument is false, + * then the clean-up will abort immediately in case of an error. + */ +void CleanOptions::setKeepGoing(bool keepGoing) +{ + d->keepGoing = keepGoing; +} + +/*! + * \brief Returns true iff the time the operation takes will be logged. + * The default is false. + */ +bool CleanOptions::logElapsedTime() const +{ + return d->logElapsedTime; +} + +/*! + * \brief Controls whether the clean-up time will be measured and logged. + */ +void CleanOptions::setLogElapsedTime(bool log) { + d->logElapsedTime = log; } } // namespace qbs diff --git a/src/lib/tools/cleanoptions.h b/src/lib/tools/cleanoptions.h index daa2d2f28..27325eb0b 100644 --- a/src/lib/tools/cleanoptions.h +++ b/src/lib/tools/cleanoptions.h @@ -31,21 +31,35 @@ #include "qbs_export.h" +#include <QSharedDataPointer> #include <QString> namespace qbs { +namespace Internal { class CleanOptionsPrivate; } class QBS_EXPORT CleanOptions { public: CleanOptions(); + CleanOptions(const CleanOptions &other); + CleanOptions &operator=(const CleanOptions &other); + ~CleanOptions(); enum CleanType { CleanupAll, CleanupTemporaries }; + CleanType cleanType() const; + void setCleanType(CleanType cleanType); - CleanType cleanType; - bool dryRun; - bool keepGoing; - bool logElapsedTime; + bool dryRun() const; + void setDryRun(bool dryRun); + + bool keepGoing() const; + void setKeepGoing(bool keepGoing); + + bool logElapsedTime() const; + void setLogElapsedTime(bool log); + +private: + QSharedDataPointer<Internal::CleanOptionsPrivate> d; }; } // namespace qbs diff --git a/src/lib/tools/codelocation.cpp b/src/lib/tools/codelocation.cpp index d72cb78b1..e81953da3 100644 --- a/src/lib/tools/codelocation.cpp +++ b/src/lib/tools/codelocation.cpp @@ -31,33 +31,76 @@ #include <QDataStream> #include <QDir> #include <QRegExp> +#include <QSharedData> +#include <QString> namespace qbs { -CodeLocation::CodeLocation() : line(-1), column(-1) -{} +class CodeLocation::CodeLocationPrivate : public QSharedData +{ +public: + QString fileName; + int line; + int column; +}; + +CodeLocation::CodeLocation() : d(new CodeLocationPrivate) +{ + d->line = d->column = -1; +} CodeLocation::CodeLocation(const QString &aFileName, int aLine, int aColumn) - : fileName(aFileName), - line(aLine), - column(aColumn) -{} + : d(new CodeLocationPrivate) +{ + d->fileName = aFileName; + d->line = aLine; + d->column = aColumn; +} + +CodeLocation::CodeLocation(const CodeLocation &other) : d(other.d) +{ +} + +CodeLocation &CodeLocation::operator=(const CodeLocation &other) +{ + d = other.d; + return *this; +} + +CodeLocation::~CodeLocation() +{ +} + +QString CodeLocation::fileName() const +{ + return d->fileName; +} + +int CodeLocation::line() const +{ + return d->line; +} + +int CodeLocation::column() const +{ + return d->column; +} bool CodeLocation::isValid() const { - return !fileName.isEmpty(); + return !fileName().isEmpty(); } QString CodeLocation::toString() const { QString str; if (isValid()) { - str = QDir::toNativeSeparators(fileName); + str = QDir::toNativeSeparators(fileName()); QString lineAndColumn; - if (line > 0 && !str.contains(QRegExp(QLatin1String(":[0-9]+$")))) - lineAndColumn += QLatin1Char(':') + QString::number(line); - if (column > 0 && !str.contains(QRegExp(QLatin1String(":[0-9]+:[0-9]+$")))) - lineAndColumn += QLatin1Char(':') + QString::number(column); + if (line() > 0 && !str.contains(QRegExp(QLatin1String(":[0-9]+$")))) + lineAndColumn += QLatin1Char(':') + QString::number(line()); + if (column() > 0 && !str.contains(QRegExp(QLatin1String(":[0-9]+:[0-9]+$")))) + lineAndColumn += QLatin1Char(':') + QString::number(column()); str += lineAndColumn; } return str; @@ -65,7 +108,8 @@ QString CodeLocation::toString() const bool operator==(const CodeLocation &cl1, const CodeLocation &cl2) { - return cl1.fileName == cl2.fileName && cl1.line == cl2.line && cl1.column == cl2.column; + return cl1.fileName() == cl2.fileName() && cl1.line() == cl2.line() + && cl1.column() == cl2.column(); } bool operator!=(const CodeLocation &cl1, const CodeLocation &cl2) @@ -75,17 +119,21 @@ bool operator!=(const CodeLocation &cl1, const CodeLocation &cl2) QDataStream &operator<<(QDataStream &s, const CodeLocation &o) { - s << o.fileName; - s << o.line; - s << o.column; + s << o.fileName(); + s << o.line(); + s << o.column(); return s; } QDataStream &operator>>(QDataStream &s, CodeLocation &o) { - s >> o.fileName; - s >> o.line; - s >> o.column; + QString fileName; + int line; + int column; + s >> fileName; + s >> line; + s >> column; + o = CodeLocation(fileName, line, column); return s; } diff --git a/src/lib/tools/codelocation.h b/src/lib/tools/codelocation.h index d0d9790ad..169cb21c2 100644 --- a/src/lib/tools/codelocation.h +++ b/src/lib/tools/codelocation.h @@ -32,10 +32,11 @@ #include "qbs_export.h" -#include <QString> +#include <QExplicitlySharedDataPointer> QT_BEGIN_NAMESPACE class QDataStream; +class QString; QT_END_NAMESPACE namespace qbs { @@ -45,13 +46,19 @@ class QBS_EXPORT CodeLocation public: CodeLocation(); CodeLocation(const QString &aFileName, int aLine = -1, int aColumn = -1); + CodeLocation(const CodeLocation &other); + CodeLocation &operator=(const CodeLocation &other); + ~CodeLocation(); + + QString fileName() const; + int line() const; + int column() const; bool isValid() const; QString toString() const; - - QString fileName; - int line; - int column; +private: + class CodeLocationPrivate; + QExplicitlySharedDataPointer<CodeLocationPrivate> d; }; QBS_EXPORT bool operator==(const CodeLocation &cl1, const CodeLocation &cl2); diff --git a/src/lib/tools/error.cpp b/src/lib/tools/error.cpp index 38796d2c6..279b74b3d 100644 --- a/src/lib/tools/error.cpp +++ b/src/lib/tools/error.cpp @@ -29,10 +29,18 @@ #include "error.h" +#include <QSharedData> #include <QStringList> namespace qbs { +class ErrorData::ErrorDataPrivate : public QSharedData +{ +public: + QString description; + CodeLocation codeLocation; +}; + /*! * \class ErrorData * \brief The \c ErrorData class describes (part of) an error resulting from a qbs operation. @@ -40,20 +48,39 @@ namespace qbs { * \sa Error */ -ErrorData::ErrorData() +ErrorData::ErrorData() : d(new ErrorDataPrivate) { } ErrorData::ErrorData(const QString &description, const CodeLocation &codeLocation) - : m_description(description) - , m_codeLocation(codeLocation) + : d(new ErrorDataPrivate) +{ + d->description = description; + d->codeLocation = codeLocation; +} + +ErrorData::ErrorData(const ErrorData &rhs) : d(rhs.d) +{ +} + +ErrorData &ErrorData::operator=(const ErrorData &other) +{ + d = other.d; + return *this; +} + +ErrorData::~ErrorData() { } -ErrorData::ErrorData(const ErrorData &rhs) - : m_description(rhs.m_description) - , m_codeLocation(rhs.m_codeLocation) +QString ErrorData::description() const { + return d->description; +} + +CodeLocation ErrorData::codeLocation() const +{ + return d->codeLocation; } /*! @@ -72,12 +99,19 @@ ErrorData::ErrorData(const ErrorData &rhs) */ QString ErrorData::toString() const { - QString str = m_codeLocation.toString(); + QString str = codeLocation().toString(); if (!str.isEmpty()) str += QLatin1Char(' '); - return str += m_description; + return str += description(); } + +class Error::ErrorPrivate : public QSharedData +{ +public: + QList<ErrorData> items; +}; + /*! * \class Error * \brief Represents an error resulting from a qbs operation. @@ -85,28 +119,37 @@ QString ErrorData::toString() const * \sa ErrorData */ -Error::Error() +Error::Error() : d(new ErrorPrivate) { } -Error::Error(const Error &rhs) - : m_data(rhs.m_data) +Error::Error(const Error &rhs) : d(rhs.d) { } -Error::Error(const QString &description, const CodeLocation &location) +Error::Error(const QString &description, const CodeLocation &location) : d(new ErrorPrivate) { append(description, location); } +Error &Error::operator =(const Error &other) +{ + d = other.d; + return *this; +} + +Error::~Error() +{ +} + void Error::append(const QString &description, const CodeLocation &location) { - m_data.append(ErrorData(description, location)); + d->items.append(ErrorData(description, location)); } void Error::prepend(const QString &description, const CodeLocation &location) { - m_data.prepend(ErrorData(description, location)); + d->items.prepend(ErrorData(description, location)); } /*! @@ -114,14 +157,14 @@ void Error::prepend(const QString &description, const CodeLocation &location) * Most often, there will be one element in this list, but there can be more e.g. to illustrate * how an error condition propagates through several source files. */ -const QList<ErrorData> &Error::entries() const +QList<ErrorData> Error::entries() const { - return m_data; + return d->items; } void Error::clear() { - m_data.clear(); + d->items.clear(); } /*! @@ -132,7 +175,7 @@ void Error::clear() QString Error::toString() const { QStringList lines; - foreach (const ErrorData &e, m_data) + foreach (const ErrorData &e, d->items) lines.append(e.toString()); return lines.join(QLatin1String("\n")); } diff --git a/src/lib/tools/error.h b/src/lib/tools/error.h index 28a703ba7..ef0515e22 100644 --- a/src/lib/tools/error.h +++ b/src/lib/tools/error.h @@ -30,28 +30,36 @@ #ifndef QBS_ERROR #define QBS_ERROR -#include <QMetaType> - #include "codelocation.h" +#include <QExplicitlySharedDataPointer> #include <QList> +#include <QMetaType> +#include <QSharedDataPointer> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE namespace qbs { +class CodeLocation; class QBS_EXPORT ErrorData { public: ErrorData(); - explicit ErrorData(const QString &description, const CodeLocation &codeLocation); + ErrorData(const QString &description, const CodeLocation &codeLocation); ErrorData(const ErrorData &rhs); + ErrorData &operator=(const ErrorData &other); + ~ErrorData(); - const QString &description() const { return m_description; } - CodeLocation codeLocation() const { return m_codeLocation; } + QString description() const; + CodeLocation codeLocation() const; QString toString() const; private: - QString m_description; - CodeLocation m_codeLocation; + class ErrorDataPrivate; + QExplicitlySharedDataPointer<ErrorDataPrivate> d; }; class QBS_EXPORT Error @@ -60,15 +68,18 @@ public: Error(); Error(const Error &rhs); Error(const QString &description, const CodeLocation &location = CodeLocation()); + Error &operator=(const Error &other); + ~Error(); void append(const QString &description, const CodeLocation &location = CodeLocation()); void prepend(const QString &description, const CodeLocation &location = CodeLocation()); - const QList<ErrorData> &entries() const; + QList<ErrorData> entries() const; void clear(); QString toString() const; private: - QList<ErrorData> m_data; + class ErrorPrivate; + QSharedDataPointer<ErrorPrivate> d; }; } // namespace qbs diff --git a/src/lib/tools/installoptions.cpp b/src/lib/tools/installoptions.cpp index c63a92c7b..e6d7da509 100644 --- a/src/lib/tools/installoptions.cpp +++ b/src/lib/tools/installoptions.cpp @@ -28,7 +28,24 @@ ****************************************************************************/ #include "installoptions.h" +#include <QSharedData> + namespace qbs { +namespace Internal { + +class InstallOptionsPrivate : public QSharedData +{ +public: + InstallOptionsPrivate() : removeExisting(false), dryRun(false), keepGoing(false) {} + + QString installRoot; + bool removeExisting; + bool dryRun; + bool keepGoing; + bool logElapsedTime; +}; + +} // namespace Internal /*! * \class InstallOptions @@ -36,50 +53,128 @@ namespace qbs { * install operations. */ - /*! - * \variable InstallOptions::dryRun - * \brief if true, qbs will not actually copy any files, but just show what would happen. - */ +InstallOptions::InstallOptions() : d(new Internal::InstallOptionsPrivate) +{ +} + +InstallOptions::InstallOptions(const InstallOptions &other) : d(other.d) +{ +} + +InstallOptions &InstallOptions::operator=(const InstallOptions &other) +{ + d = other.d; + return *this; +} + +InstallOptions::~InstallOptions() +{ +} /*! - * \variable InstallOptions::keepGoing - * \brief if true, do not abort on errors - * If a file cannot be copied e.g. due to a permission problem, a warning will be printed and - * the installation will continue. If this flag is not set, then the installation will abort - * immediately in case of an error. + * \brief The default install root, relative to the build directory. */ +QString InstallOptions::defaultInstallRoot() +{ + return QLatin1String("install-root"); +} /*! - * \variable InstallOptions::installRoot - * \brief the base directory for the installation + * Returns the base directory for the installation. * All "qbs.installDir" paths are relative to this root. If the string is empty, the value of * qbs.sysroot will be used. If that is also empty, the base directory is * "<build dir>/install-root". + * The default is empty. */ +QString InstallOptions::installRoot() const +{ + return d->installRoot; +} - /*! - * \variable InstallOptions::removeFirst - * \brief if true, removes the installRoot before installing any files. - * \note qbs may do some safety checks here and refuse to remove certain directories such as - * a user's home directory. You should still be careful with this option, since it - * deletes recursively. - */ +/*! + * \brief Sets the base directory for the installation. + * \note The argument must either be an empty string or an absolute path to a directory + * (which might not yet exists, in which case it will be created). + */ +void InstallOptions::setInstallRoot(const QString &installRoot) +{ + d->installRoot = installRoot; +} - /*! - * \variable InstallOptions::logElapsedTime - * \brief true iff the time the operation takes should be logged - */ +/*! + * \brief Returns true iff an existing installation will be removed prior to installing. + * The default is false. + */ +bool InstallOptions::removeExistingInstallation() const +{ + return d->removeExisting; +} -InstallOptions::InstallOptions() : removeFirst(false), dryRun(false), keepGoing(false) +/*! + * Controls whether to remove an existing installation before installing. + * \note qbs may do some safety checks and refuse to remove certain directories such as + * a user's home directory. You should still be careful with this option, since it + * deletes recursively. + */ +void InstallOptions::setRemoveExistingInstallation(bool removeExisting) { + d->removeExisting = removeExisting; } /*! - * \brief The default install root, relative to the build directory. + * \brief Returns true iff qbs will not actually copy any files, but just show what would happen. + * The default is false. */ -QString InstallOptions::defaultInstallRoot() +bool InstallOptions::dryRun() const { - return QLatin1String("install-root"); + return d->dryRun; +} + +/*! + * \brief Controls whether installation will actually take place. + * If the argument is true, then qbs will emit information about which files would be copied + * instead of actually doing it. + */ +void InstallOptions::setDryRun(bool dryRun) +{ + d->dryRun = dryRun; +} + +/*! + * Returns true iff installation will continue if an error occurs. + * The default is false. + */ +bool InstallOptions::keepGoing() const +{ + return d->keepGoing; +} + +/*! + * \brief Controls whether to abort on errors. + * If the argument is true, then if a file cannot be copied e.g. due to a permission problem, + * a warning will be printed and the installation will continue. If the argument is false, + * then the installation will abort immediately in case of an error. + */ +void InstallOptions::setKeepGoing(bool keepGoing) +{ + d->keepGoing = keepGoing; +} + +/*! + * \brief Returns true iff the time the operation takes will be logged. + * The default is false. + */ +bool InstallOptions::logElapsedTime() const +{ + return d->logElapsedTime; +} + +/*! + * \brief Controls whether the installation time will be measured and logged. + */ +void InstallOptions::setLogElapsedTime(bool logElapsedTime) +{ + d->logElapsedTime = logElapsedTime; } } // namespace qbs diff --git a/src/lib/tools/installoptions.h b/src/lib/tools/installoptions.h index 1f63b8c44..cf672c705 100644 --- a/src/lib/tools/installoptions.h +++ b/src/lib/tools/installoptions.h @@ -31,21 +31,38 @@ #include "qbs_export.h" +#include <QSharedDataPointer> #include <QString> namespace qbs { +namespace Internal { class InstallOptionsPrivate; } class QBS_EXPORT InstallOptions { public: InstallOptions(); + InstallOptions(const InstallOptions &other); + InstallOptions &operator=(const InstallOptions &other); + ~InstallOptions(); static QString defaultInstallRoot(); - QString installRoot; - bool removeFirst; - bool dryRun; - bool keepGoing; - bool logElapsedTime; + QString installRoot() const; + void setInstallRoot(const QString &installRoot); + + bool removeExistingInstallation() const; + void setRemoveExistingInstallation(bool removeExisting); + + bool dryRun() const; + void setDryRun(bool dryRun); + + bool keepGoing() const; + void setKeepGoing(bool keepGoing); + + bool logElapsedTime() const; + void setLogElapsedTime(bool logElapsedTime); + +private: + QSharedDataPointer<Internal::InstallOptionsPrivate> d; }; } // namespace qbs diff --git a/src/lib/tools/processresult.cpp b/src/lib/tools/processresult.cpp new file mode 100644 index 000000000..fe59962e0 --- /dev/null +++ b/src/lib/tools/processresult.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#include "processresult.h" +#include "processresult_p.h" + +/*! + * \class SetupProjectParameters + * \brief The \c ProcessResult class describes a finished qbs process command. + */ + +namespace qbs { + +ProcessResult::ProcessResult() : d(new Internal::ProcessResultPrivate) +{ +} + +ProcessResult::ProcessResult(const ProcessResult &other) : d(other.d) +{ +} + +ProcessResult &ProcessResult::operator=(const ProcessResult &other) +{ + d = other.d; + return *this; +} + +ProcessResult::~ProcessResult() +{ +} + +/*! + * \brief Returns true iff the command finished successfully. + */ +bool ProcessResult::success() const +{ + return d->success; +} + +/*! + * \brief Returns the file path of the executable that was run. + */ +QString ProcessResult::executableFilePath() const +{ + return d->executableFilePath; +} + +/*! + * \brief Returns the command-line arguments with which the command was invoked. + */ +QStringList ProcessResult::arguments() const +{ + return d->arguments; +} + +/*! + * \brief Returns the working directory of the invoked command. + */ +QString ProcessResult::workingDirectory() const +{ + return d->workingDirectory; +} + +/*! + * \brief Returns the exit status of the command. + */ +QProcess::ExitStatus ProcessResult::exitStatus() const +{ + return d->exitStatus; +} + +/*! + * \brief Returns the exit code of the command. + */ +int ProcessResult::exitCode() const +{ + return d->exitCode; +} + +/*! + * \brief Returns the data the command wrote to the standard output channel. + */ +QStringList ProcessResult::stdOut() const +{ + return d->stdOut; +} + +/*! + * \brief Returns the data the command wrote to the standard error channel. + */ +QStringList ProcessResult::stdErr() const +{ + return d->stdErr; +} + +} // namespace qbs diff --git a/src/lib/tools/processresult.h b/src/lib/tools/processresult.h index 37d0d9e2f..a2efba863 100644 --- a/src/lib/tools/processresult.h +++ b/src/lib/tools/processresult.h @@ -31,25 +31,38 @@ #include "qbs_export.h" +#include <QExplicitlySharedDataPointer> #include <QMetaType> #include <QProcess> #include <QString> #include <QStringList> namespace qbs { +namespace Internal { +class ProcessCommandExecutor; +class ProcessResultPrivate; +} -class QBS_EXPORT ProcessResult { +class QBS_EXPORT ProcessResult +{ + friend class qbs::Internal::ProcessCommandExecutor; public: - bool success; + ProcessResult(); + ProcessResult(const ProcessResult &other); + ProcessResult &operator=(const ProcessResult &other); + ~ProcessResult(); - QString binary; - QStringList arguments; - QString workingDirectory; + bool success() const; + QString executableFilePath() const; + QStringList arguments() const; + QString workingDirectory() const; + QProcess::ExitStatus exitStatus() const; + int exitCode() const; + QStringList stdOut() const; + QStringList stdErr() const; - QProcess::ExitStatus exitStatus; - int exitCode; - QStringList stdOut; - QStringList stdErr; +private: + QExplicitlySharedDataPointer<Internal::ProcessResultPrivate> d; }; } // namespace qbs diff --git a/src/lib/tools/processresult_p.h b/src/lib/tools/processresult_p.h new file mode 100644 index 000000000..0a4b443b9 --- /dev/null +++ b/src/lib/tools/processresult_p.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Build Suite. +** +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ +#ifndef QBS_PROCESSRESULT_P_H +#define QBS_PROCESSRESULT_P_H + +#include <QSharedData> +#include <QStringList> +#include <QProcess> + +namespace qbs { +namespace Internal { +class ProcessResultPrivate : public QSharedData +{ +public: + bool success; + + QString executableFilePath; + QStringList arguments; + QString workingDirectory; + + QProcess::ExitStatus exitStatus; + int exitCode; + QStringList stdOut; + QStringList stdErr; +}; + +} // namespace Internal +} // namespace qbs + +#endif // Include guard. diff --git a/src/lib/tools/qbsassert.cpp b/src/lib/tools/qbsassert.cpp index 5fa53d5f4..d9e1f78d7 100644 --- a/src/lib/tools/qbsassert.cpp +++ b/src/lib/tools/qbsassert.cpp @@ -30,6 +30,8 @@ #include "qbsassert.h" #include "error.h" +#include <QString> + namespace qbs { namespace Internal { diff --git a/src/lib/tools/setupprojectparameters.cpp b/src/lib/tools/setupprojectparameters.cpp index 399149607..406a5ffe4 100644 --- a/src/lib/tools/setupprojectparameters.cpp +++ b/src/lib/tools/setupprojectparameters.cpp @@ -29,57 +29,194 @@ #include "setupprojectparameters.h" namespace qbs { - -SetupProjectParameters::SetupProjectParameters() - : ignoreDifferentProjectFilePath(false), dryRun(false), logElapsedTime(false) -{ -} +namespace Internal { /*! * \class SetupProjectParameters * \brief The \c SetupProjectParameters class comprises data required to set up a qbs project. */ +class SetupProjectParametersPrivate : public QSharedData +{ +public: + SetupProjectParametersPrivate() + : ignoreDifferentProjectFilePath(false), dryRun(false), logElapsedTime(false) + { + } + + QString projectFilePath; + QString buildRoot; + QStringList searchPaths; + QStringList pluginPaths; + QVariantMap buildConfiguration; + bool ignoreDifferentProjectFilePath; + bool dryRun; + bool logElapsedTime; +}; + +} // namespace Internal + +SetupProjectParameters::SetupProjectParameters() : d(new Internal::SetupProjectParametersPrivate) +{ +} + +SetupProjectParameters::SetupProjectParameters(const SetupProjectParameters &other) : d(other.d) +{ +} + +SetupProjectParameters::~SetupProjectParameters() +{ +} + +SetupProjectParameters &SetupProjectParameters::operator=(const SetupProjectParameters &other) +{ + d = other.d; + return *this; +} + /*! - * \variable SetupProjectParameters::projectFilePath - * \brief The absolute path to the qbs project file. + * \brief Returns the absolute path to the qbs project file. * This file typically has a ".qbs" suffix. */ +QString SetupProjectParameters::projectFilePath() const +{ + return d->projectFilePath; +} + +/*! + * \brief Sets the path to the main project file. + * \note The argument must be an absolute file path. + */ +void SetupProjectParameters::setProjectFilePath(const QString &projectFilePath) +{ + d->projectFilePath = projectFilePath; +} /*! - * \variable SetupProjectParameters::buildRoot - * \brief The base path of where to put the build artifacts. + * \brief Returns the base path of where to put the build artifacts and store the build graph. + */ +QString SetupProjectParameters::buildRoot() const +{ + return d->buildRoot; +} + +/*! + * \brief Sets the base path of where to put the build artifacts and store the build graph. * The same base path can be used for several build profiles of the same project without them * interfering with each other. * It might look as if this parameter would not be needed at the time of setting up the project, - * but keep in mind that the project information might already exist on disk, in which case + * but keep in mind that the project information could already exist on disk, in which case * loading it will be much faster than setting up the project from scratch. + * \note The argument must be an absolute path to a directory. */ +void SetupProjectParameters::setBuildRoot(const QString &buildRoot) +{ + d->buildRoot = buildRoot; +} /*! - * \variable SetupProjectParameters::searchPaths * \brief Where to look for modules and items to import. */ +QStringList SetupProjectParameters::searchPaths() const +{ + return d->searchPaths; +} + +/*! + * \brief Sets the information about where to look for modules and items to import. + * \note The elements of the list must be absolute paths to directories. + */ +void SetupProjectParameters::setSearchPaths(const QStringList &searchPaths) +{ + d->searchPaths = searchPaths; +} /*! - * \variable SetupProjectParameters::pluginPaths * \brief Where to look for plugins. */ +QStringList SetupProjectParameters::pluginPaths() const +{ + return d->pluginPaths; +} + +/*! + * \brief Sets the information about where to look for plugins. + * \note The elements of the list must be absolute paths to directories. + */ +void SetupProjectParameters::setPluginPaths(const QStringList &pluginPaths) +{ + d->pluginPaths = pluginPaths; +} /*! - * \variable SetupProjectParameters::buildConfiguration * \brief The collection of properties to use for resolving the project. */ +QVariantMap SetupProjectParameters::buildConfiguration() const +{ + return d->buildConfiguration; +} + +/*! + * Sets the collection of properties to use for resolving the project. + */ +void SetupProjectParameters::setBuildConfiguration(const QVariantMap &buildConfiguration) +{ + d->buildConfiguration = buildConfiguration; +} + +/*! + * \variable SetupProjectParameters::ignoreDifferentProjectFilePath + * \brief Returns true iff the saved build graph should be used even if its path to the + * project file is different from \c SetupProjectParameters::projectFilePath() + */ +bool SetupProjectParameters::ignoreDifferentProjectFilePath() const +{ + return d->ignoreDifferentProjectFilePath; +} + +/*! + * \brief Controls whether the path to the main project file may be different from the one + * stored in a possible build graph file. + * The default is false. + */ +void SetupProjectParameters::setIgnoreDifferentProjectFilePath(bool doIgnore) +{ + d->ignoreDifferentProjectFilePath = doIgnore; +} /*! - * \variable SetupProjectParameters::ignoreDifferentProjectFilePath - * \brief true iff the saved build graph should be used even if its path to the project file - * is different from \c projectFilePath + * \brief if true, qbs will not store the build graph of the resolved project. */ +bool SetupProjectParameters::dryRun() const +{ + return d->dryRun; +} /*! - * \variable SetupProjectParameters::logElapsedTime - * \brief true iff the time the operation takes should be logged + * \brief Controls whether the build graph will be stored. + * If the argument is true, qbs will not store the build graph after resolving the project. + * The default is false. */ +void SetupProjectParameters::setDryRun(bool dryRun) +{ + d->dryRun = dryRun; +} + + /*! + * \brief Returns true iff the time the operation takes should be logged + */ +bool SetupProjectParameters::logElapsedTime() const +{ + return d->logElapsedTime; +} + +/*! + * Controls whether to log the time taken up for resolving the project. + * The default is false. + */ +void SetupProjectParameters::setLogElapsedTime(bool logElapsedTime) +{ + d->logElapsedTime = logElapsedTime; +} } // namespace qbs diff --git a/src/lib/tools/setupprojectparameters.h b/src/lib/tools/setupprojectparameters.h index 81adbf684..f38f6230c 100644 --- a/src/lib/tools/setupprojectparameters.h +++ b/src/lib/tools/setupprojectparameters.h @@ -31,24 +31,48 @@ #include "qbs_export.h" +#include <QSharedDataPointer> #include <QStringList> #include <QVariantMap> namespace qbs { +namespace Internal { class SetupProjectParametersPrivate; } class QBS_EXPORT SetupProjectParameters { public: SetupProjectParameters(); + SetupProjectParameters(const SetupProjectParameters &other); + ~SetupProjectParameters(); - QString projectFilePath; - QString buildRoot; - QStringList searchPaths; - QStringList pluginPaths; - QVariantMap buildConfiguration; - bool ignoreDifferentProjectFilePath; - bool dryRun; - bool logElapsedTime; + SetupProjectParameters &operator=(const SetupProjectParameters &other); + + QString projectFilePath() const; + void setProjectFilePath(const QString &projectFilePath); + + QString buildRoot() const; + void setBuildRoot(const QString &buildRoot); + + QStringList searchPaths() const; + void setSearchPaths(const QStringList &searchPaths); + + QStringList pluginPaths() const; + void setPluginPaths(const QStringList &pluginPaths); + + QVariantMap buildConfiguration() const; + void setBuildConfiguration(const QVariantMap &buildConfiguration); + + bool ignoreDifferentProjectFilePath() const; + void setIgnoreDifferentProjectFilePath(bool doIgnore); + + bool dryRun() const; + void setDryRun(bool dryRun); + + bool logElapsedTime() const; + void setLogElapsedTime(bool logElapsedTime); + +private: + QSharedDataPointer<Internal::SetupProjectParametersPrivate> d; }; } // namespace qbs diff --git a/src/lib/tools/tools.pri b/src/lib/tools/tools.pri index b7e7eaaa4..730641376 100644 --- a/src/lib/tools/tools.pri +++ b/src/lib/tools/tools.pri @@ -13,6 +13,7 @@ HEADERS += \ $$PWD/preferences.h \ $$PWD/profile.h \ $$PWD/processresult.h \ + $$PWD/processresult_p.h \ $$PWD/progressobserver.h \ $$PWD/propertyfinder.h \ $$PWD/hostosinfo.h \ @@ -36,6 +37,7 @@ SOURCES += \ $$PWD/scripttools.cpp \ $$PWD/settings.cpp \ $$PWD/preferences.cpp \ + $$PWD/processresult.cpp \ $$PWD/profile.cpp \ $$PWD/progressobserver.cpp \ $$PWD/propertyfinder.cpp \ diff --git a/tests/auto/cmdlineparser/tst_cmdlineparser.cpp b/tests/auto/cmdlineparser/tst_cmdlineparser.cpp index cccbb636b..41a09d22a 100644 --- a/tests/auto/cmdlineparser/tst_cmdlineparser.cpp +++ b/tests/auto/cmdlineparser/tst_cmdlineparser.cpp @@ -70,8 +70,8 @@ private slots: QCOMPARE(ConsoleLogger::instance().logSink()->logLevel(), LoggerTrace); QCOMPARE(parser.command(), BuildCommandType); QCOMPARE(parser.products(), QStringList() << "blubb"); - QCOMPARE(parser.buildOptions().changedFiles.count(), 2); - QVERIFY(parser.buildOptions().keepGoing); + QCOMPARE(parser.buildOptions().changedFiles().count(), 2); + QVERIFY(parser.buildOptions().keepGoing()); QVERIFY(parser.force()); QVERIFY(!parser.logTime()); QCOMPARE(parser.buildConfigurations().count(), 1); |
