forked from qt-creator/qt-creator
Extend Coco plugin for QMake/CMake project instrumentation
The Coco plugin now can also configure QMake and CMake projects for the use with Coco. (COCO-1782) * There is a new global preferences page to set the Coco directory. (But the plugin also searches automatically for the active Coco installation, so using the page should rarely be necessary.) * There is a project settings page where the code coverage can be configured, especially CoverageScanner options set. * Code coverage is enabled by changing the build settings of a project so that the build tool reads a special file at the beginning (cocoplugin.prf or cocoplugin.cmake), which replaces the normal compiler calls with calls of the Coco compiler wrappers. The CoverageScanner options are part of this file. * An additional, ficticious build step appears in the build menu of QMake and CMake projects, with a button to switch coverage on or off. * Added documentation * The class CMakeBuildSystem has been made publicly accessible and some member functions added so that the build settings chanbe chenged. [ChangeLog][coco] Added to the existing Coco plugin the ability to configure CMake and QMake projects for code coverage. Change-Id: I70a351b79b89bef3c25f81bb4b62ac59dc787645 Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
BIN
doc/qtcreator/images/qtcreator-coco-buildstep.png
Normal file
BIN
doc/qtcreator/images/qtcreator-coco-buildstep.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
BIN
doc/qtcreator/images/qtcreator-coco-configpage.png
Normal file
BIN
doc/qtcreator/images/qtcreator-coco-configpage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 7.2 KiB |
@@ -7,28 +7,119 @@
|
||||
|
||||
\ingroup creator-how-to-analyze
|
||||
|
||||
\title Check code coverage
|
||||
\title Measure and check code coverage
|
||||
|
||||
With Coco CoverageBrowser, you can analyze the test coverage by loading an
|
||||
instrumentation database (a .csmes file), which was generated by Coco
|
||||
CoverageScanner. The experimental Coco plugin is currently supported only on
|
||||
Windows, with Coco version 6.0, or later.
|
||||
With Coco, you can measure and the code coverage of tests. The Coco plugin
|
||||
supports the setup of a project for code coverage and the display of the
|
||||
coverage inside Qt Creator.
|
||||
|
||||
To use the plugin, you must download and install Coco.
|
||||
To use the plugin, you must download and install Coco version 6.0 or later.
|
||||
|
||||
\note Enable the Coco plugin to use it.
|
||||
|
||||
\section1 Configure Coco
|
||||
\section1 Configuring the plugin
|
||||
|
||||
There is a settings page at \preferences > \uicontrol Coco with which you
|
||||
can set the directory in which Coco is installed. But in most cases, the default
|
||||
settings need not to be changed.
|
||||
|
||||
\section1 Measure code coverage
|
||||
|
||||
With the Coco plugin, it is possible to set up code coverage easily for Qt Creator
|
||||
projects that are built with QMake or CMake.
|
||||
|
||||
The general idea is that you take an existing build configuration, like "Debug",
|
||||
clone it with a new name (like "DebugCoverage") and then use the plugin to
|
||||
configure it for the use with Coco. Switching back and forth between coverage
|
||||
and normal builds on the same build configuration is not recommended.
|
||||
|
||||
\section2 Components of the plugin
|
||||
|
||||
With the plugin enabled, C/C++ projects get
|
||||
\list
|
||||
\li A project settings menu at \uicontrol Projects > \uicontrol {Project settings}
|
||||
> \uicontrol {Coco Code Coverage} with which you can enable and configure
|
||||
code coverage.
|
||||
\li In the Build Settings, an additional pseudo build step that shows whether
|
||||
code coverage was enabled. There is also a button to directly disable or
|
||||
enable code coverage from this build step.
|
||||
|
||||
\image qtcreator-coco-buildstep.png {Ficticious build step for code coverage}
|
||||
\endlist
|
||||
|
||||
If code coverage is enabled, the plugin generates a \e {settings} file that is read
|
||||
by the build tool before the other configuration files and which changes the
|
||||
build process so that the Coco compiler wrappers are used instead of the original
|
||||
compiler. The settings file is always located in the root directory of the
|
||||
project sources. It also contains the coverage flags and possible overrides and
|
||||
can be checked in into version control to preserve the settings.
|
||||
|
||||
\section2 The Project settings page
|
||||
|
||||
\image qtcreator-coco-configpage.png {Settings page}
|
||||
|
||||
The pages for QMake and CMake projects do not differ very much. They contain:
|
||||
\list
|
||||
\li A checkbox to enable and disable code coverage.
|
||||
\li A field to enter code coverage options. There are no settings that are
|
||||
needed to enable code coverage. Below the field are buttons:
|
||||
\list
|
||||
\li \uicontrol {Exclude file...} to exclude a file from instrumentation
|
||||
more easily.
|
||||
\li \uicontrol {Exclude directory...} to exclude a directory from
|
||||
instrumentation more easily.
|
||||
\li \uicontrol Override to open another entry field in which you can
|
||||
enter additional commands at the end of the settings file. It is
|
||||
meant for special cases in which the usual configuration flags are
|
||||
not enough.
|
||||
\endlist
|
||||
\li A button \uicontrol Revert to reload the coverage settings from the current
|
||||
settings file.
|
||||
\li A button \uicontrol Save or \uicontrol {Save & Re-configure} to write
|
||||
the settings to the settings file and reconfigure the project, if
|
||||
necessary.
|
||||
\li A list with the project build settings that were changed by the plugin.
|
||||
\endlist
|
||||
|
||||
\section2 QMake projects
|
||||
|
||||
The settings file is \c {cocoplugin.prf}. It is a QMake "feature file".
|
||||
|
||||
For a command line build, \c {qmake} must be run with the additional options
|
||||
\tt {CONFIG+=cocoplugin COCOPATH=\e{<Coco directory>}}. It is also necessary
|
||||
to set the environment variable \c {QMAKEFEATURES} to the directory in which
|
||||
\c {cocoplugin.prf} is located.
|
||||
|
||||
\section2 CMake projects
|
||||
|
||||
The settings file is \c {cocoplugin.cmake}. It is a CMake cache preload script.
|
||||
Apart from this file, the "compiler files" \c {cocoplugin-gcc.cmake},
|
||||
\c {cocoplugin-clang.cmake} and \c {cocoplugin-visualstudio.cmake} are created
|
||||
in the same directory. They are needed for a command line build.
|
||||
|
||||
In a command-line build, run CMake in the form
|
||||
"\tt {cmake \e{<other options>} -C\e{<project dir>}/cocoplugin-gcc.cmake}"
|
||||
(if you are compiling with GCC). The file \c {cocoplugin-gcc.cmake} includes
|
||||
then \c {cocoplugin.cmake}.
|
||||
|
||||
If you use a compiler different from GCC, clang or Visual Studio, one of the
|
||||
compiler files must be modified for the new compiler.
|
||||
|
||||
\section1 Check code coverage
|
||||
|
||||
With the help of Coco CoverageBrowser, you can analyze the test coverage by
|
||||
loading an instrumentation database (a \c .csmes file), which was generated by
|
||||
Coco CoverageScanner.
|
||||
|
||||
\section2 Configure Coco
|
||||
|
||||
\list 1
|
||||
\li Go to \uicontrol Analyze > \uicontrol {Squish Coco}.
|
||||
\image qtcreator-coco.png {Coco CoverageBrowser and CSMes file}
|
||||
\li In \uicontrol {CoverageBrowser}, enter the path to the Coco
|
||||
coverage browser to use for analyzing a .csmes file.
|
||||
\li In \uicontrol CSMes, select the instrumentation database to load.
|
||||
\li Select \uicontrol Open to start CoverageBrowser.
|
||||
\li In CoverageBrowser, go to \uicontrol File >
|
||||
\uicontrol {Load Execution Report} and select the .csexe for the
|
||||
\uicontrol {Load Execution Report} and select the \c .csexe file for the
|
||||
coverage scan.
|
||||
\image coco-coveragebrowser-load-execution-report.png {Load Execution Report dialog}
|
||||
\li To keep the execution report, clear
|
||||
@@ -39,7 +130,7 @@
|
||||
after the code in \uicontrol Edit mode. You can change the fonts and colors
|
||||
used for different types of results.
|
||||
|
||||
\section1 Changing Fonts and Colors
|
||||
\section2 Changing Fonts and Colors
|
||||
|
||||
To change the default fonts and colors, go to \preferences >
|
||||
\uicontrol {Text Editor} > \uicontrol {Font & Colors}.
|
||||
|
@@ -19,9 +19,11 @@ namespace ProjectExplorer {
|
||||
class Project;
|
||||
}
|
||||
|
||||
namespace CMakeProjectManager::Internal {
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
class CMakeBuildSystem;
|
||||
}
|
||||
|
||||
namespace CMakeProjectManager::Internal {
|
||||
|
||||
class BuildDirParameters
|
||||
{
|
||||
|
@@ -117,6 +117,8 @@ public:
|
||||
void setError(const QString &message);
|
||||
void setWarning(const QString &message);
|
||||
|
||||
void updateInitialCMakeArguments();
|
||||
|
||||
private:
|
||||
void updateButtonState();
|
||||
void updateAdvancedCheckBox();
|
||||
@@ -135,7 +137,6 @@ private:
|
||||
|
||||
void batchEditConfiguration();
|
||||
void reconfigureWithInitialParameters();
|
||||
void updateInitialCMakeArguments();
|
||||
void kitCMakeConfiguration();
|
||||
void updateConfigureDetailsWidgetsSummary(
|
||||
const QStringList &configurationArguments = QStringList());
|
||||
@@ -1838,7 +1839,19 @@ QString CMakeBuildSystem::warning() const
|
||||
|
||||
NamedWidget *CMakeBuildConfiguration::createConfigWidget()
|
||||
{
|
||||
return new CMakeBuildSettingsWidget(this);
|
||||
m_configWidget = new CMakeBuildSettingsWidget(this);
|
||||
return m_configWidget;
|
||||
}
|
||||
|
||||
void CMakeBuildConfiguration::updateInitialCMakeArguments()
|
||||
{
|
||||
Q_ASSERT(m_configWidget);
|
||||
m_configWidget->updateInitialCMakeArguments();
|
||||
}
|
||||
|
||||
QStringList CMakeBuildConfiguration::initialCMakeOptions() const
|
||||
{
|
||||
return initialCMakeArguments.allValues();
|
||||
}
|
||||
|
||||
CMakeConfig CMakeBuildConfiguration::signingFlags() const
|
||||
|
@@ -14,10 +14,10 @@
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
class CMakeProject;
|
||||
class CMakeBuildSystem;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class CMakeBuildSystem;
|
||||
class CMakeBuildSettingsWidget;
|
||||
class CMakeProjectImporter;
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
void setRestrictedBuildTarget(const QString &buildTarget);
|
||||
|
||||
Utils::Environment configureEnvironment() const;
|
||||
Internal::CMakeBuildSystem *cmakeBuildSystem() const;
|
||||
CMakeBuildSystem *cmakeBuildSystem() const;
|
||||
|
||||
QStringList additionalCMakeArguments() const;
|
||||
void setAdditionalCMakeArguments(const QStringList &args);
|
||||
@@ -90,6 +90,9 @@ public:
|
||||
QtSupport::QmlDebuggingAspect qmlDebugging{this};
|
||||
Internal::ConfigureEnvironmentAspect configureEnv{this, this};
|
||||
|
||||
void updateInitialCMakeArguments();
|
||||
QStringList initialCMakeOptions() const;
|
||||
|
||||
signals:
|
||||
void signingFlagsChanged();
|
||||
void configureEnvironmentChanged();
|
||||
@@ -105,11 +108,12 @@ private:
|
||||
void setBuildPresetToBuildSteps(const ProjectExplorer::Target *target);
|
||||
void filterConfigArgumentsFromAdditionalCMakeArguments();
|
||||
|
||||
Internal::CMakeBuildSystem *m_buildSystem = nullptr;
|
||||
CMakeBuildSystem *m_buildSystem = nullptr;
|
||||
Internal::CMakeBuildSettingsWidget *m_configWidget = nullptr;
|
||||
QStringList m_unrestrictedBuildTargets;
|
||||
|
||||
friend class Internal::CMakeBuildSettingsWidget;
|
||||
friend class Internal::CMakeBuildSystem;
|
||||
friend class CMakeBuildSystem;
|
||||
};
|
||||
|
||||
class CMAKE_EXPORT CMakeBuildConfigurationFactory
|
||||
|
@@ -62,8 +62,9 @@
|
||||
using namespace ProjectExplorer;
|
||||
using namespace TextEditor;
|
||||
using namespace Utils;
|
||||
using namespace CMakeProjectManager::Internal;
|
||||
|
||||
namespace CMakeProjectManager::Internal {
|
||||
namespace CMakeProjectManager {
|
||||
|
||||
static Q_LOGGING_CATEGORY(cmakeBuildSystemLog, "qtc.cmake.buildsystem", QtWarningMsg);
|
||||
|
||||
@@ -2523,4 +2524,4 @@ ExtraCompiler *CMakeBuildSystem::findExtraCompiler(const ExtraCompilerFilter &fi
|
||||
return Utils::findOrDefault(m_extraCompilers, filter);
|
||||
}
|
||||
|
||||
} // CMakeProjectManager::Internal
|
||||
} // CMakeProjectManager
|
||||
|
@@ -29,13 +29,11 @@ namespace CMakeProjectManager {
|
||||
class CMakeBuildConfiguration;
|
||||
class CMakeProject;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// CMakeBuildSystem:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class CMakeBuildSystem final : public ProjectExplorer::BuildSystem
|
||||
class CMAKE_EXPORT CMakeBuildSystem final : public ProjectExplorer::BuildSystem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -157,7 +155,7 @@ private:
|
||||
Utils::FilePaths *);
|
||||
bool addTsFiles(ProjectExplorer::Node *context, const Utils::FilePaths &filePaths,
|
||||
Utils::FilePaths *);
|
||||
bool renameFile(CMakeTargetNode *context,
|
||||
bool renameFile(Internal::CMakeTargetNode *context,
|
||||
const Utils::FilePath &oldFilePath,
|
||||
const Utils::FilePath &newFilePath, bool &shouldRunCMake);
|
||||
|
||||
@@ -175,10 +173,10 @@ private:
|
||||
};
|
||||
void reparse(int reparseParameters);
|
||||
QString reparseParametersString(int reparseFlags);
|
||||
void setParametersAndRequestParse(const BuildDirParameters ¶meters,
|
||||
void setParametersAndRequestParse(const Internal::BuildDirParameters ¶meters,
|
||||
const int reparseParameters);
|
||||
|
||||
bool mustApplyConfigurationChangesArguments(const BuildDirParameters ¶meters) const;
|
||||
bool mustApplyConfigurationChangesArguments(const Internal::BuildDirParameters ¶meters) const;
|
||||
|
||||
// State handling:
|
||||
// Parser states:
|
||||
@@ -208,7 +206,7 @@ private:
|
||||
|
||||
void wireUpConnections();
|
||||
|
||||
void ensureBuildDirectory(const BuildDirParameters ¶meters);
|
||||
void ensureBuildDirectory(const Internal::BuildDirParameters ¶meters);
|
||||
void stopParsingAndClearState();
|
||||
void becameDirty();
|
||||
|
||||
@@ -243,7 +241,7 @@ private:
|
||||
ProjectExplorer::ProjectUpdater *m_cppCodeModelUpdater = nullptr;
|
||||
QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers;
|
||||
QList<CMakeBuildTarget> m_buildTargets;
|
||||
QSet<CMakeFileInfo> m_cmakeFiles;
|
||||
QSet<Internal::CMakeFileInfo> m_cmakeFiles;
|
||||
QHash<QString, Utils::Link> m_cmakeSymbolsHash;
|
||||
QHash<QString, Utils::Link> m_dotCMakeFilesHash;
|
||||
QHash<QString, Utils::Link> m_findPackagesFilesHash;
|
||||
@@ -254,9 +252,9 @@ private:
|
||||
QHash<QString, ProjectFileArgumentPosition> m_filesToBeRenamed;
|
||||
|
||||
// Parsing state:
|
||||
BuildDirParameters m_parameters;
|
||||
Internal::BuildDirParameters m_parameters;
|
||||
int m_reparseParameters = REPARSE_DEFAULT;
|
||||
FileApiReader m_reader;
|
||||
Internal::FileApiReader m_reader;
|
||||
mutable bool m_isHandlingError = false;
|
||||
|
||||
// CTest integration
|
||||
@@ -271,5 +269,4 @@ private:
|
||||
QString m_warning;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace CMakeProjectManager
|
||||
|
@@ -1,7 +1,51 @@
|
||||
add_qtc_plugin(Coco
|
||||
PLUGIN_DEPENDS Core LanguageClient
|
||||
PLUGIN_DEPENDS
|
||||
QtCreator::Core
|
||||
QtCreator::LanguageClient
|
||||
QtCreator::ProjectExplorer
|
||||
QtCreator::QmakeProjectManager
|
||||
DEPENDS
|
||||
QtCreator::CMakeProjectManager
|
||||
QtCreator::ExtensionSystem
|
||||
SOURCES
|
||||
cocolanguageclient.cpp cocolanguageclient.h
|
||||
Coco.json.in
|
||||
cocobuild/buildsettings.cpp
|
||||
cocobuild/buildsettings.h
|
||||
cocobuild/cmakemodificationfile.cpp
|
||||
cocobuild/cmakemodificationfile.h
|
||||
cocobuild/cococmakesettings.cpp
|
||||
cocobuild/cococmakesettings.h
|
||||
cocobuild/cocobuildstep.cpp
|
||||
cocobuild/cocobuildstep.h
|
||||
cocobuild/cocoprojectwidget.cpp
|
||||
cocobuild/cocoprojectwidget.h
|
||||
cocobuild/modificationfile.cpp
|
||||
cocobuild/modificationfile.h
|
||||
cocobuild/qmakefeaturefile.cpp
|
||||
cocobuild/qmakefeaturefile.h
|
||||
cocobuild/cocoqmakesettings.cpp
|
||||
cocobuild/cocoqmakesettings.h
|
||||
cocolanguageclient.cpp
|
||||
cocolanguageclient.h
|
||||
cocoplugin.cpp
|
||||
cocoplugin.qrc
|
||||
cocoplugin_global.h
|
||||
cocopluginconstants.h
|
||||
cocotr.h
|
||||
common.cpp
|
||||
common.h
|
||||
files/cocoplugin-clang.cmake
|
||||
files/cocoplugin-gcc.cmake
|
||||
files/cocoplugin-visualstudio.cmake
|
||||
files/cocoplugin.cmake
|
||||
files/cocoplugin.prf
|
||||
images/SquishCoco_48x48.png
|
||||
settings/cocoinstallation.cpp
|
||||
settings/cocoinstallation.h
|
||||
settings/cocoprojectsettingswidget.cpp
|
||||
settings/cocoprojectsettingswidget.h
|
||||
settings/globalsettings.cpp
|
||||
settings/globalsettings.h
|
||||
settings/globalsettingspage.cpp
|
||||
settings/globalsettingspage.h
|
||||
)
|
||||
|
@@ -15,9 +15,10 @@
|
||||
"",
|
||||
"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this plugin. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html."
|
||||
],
|
||||
"Description" : "Access the Coco CoverageBrowser.",
|
||||
"Description" : "Configure Coco and access the results",
|
||||
"LongDescription" : [
|
||||
"View the results from the Coco CoverageBrowser to make tests more efficient and complete."
|
||||
"Configure CMake and QMake projects for code coverage.",
|
||||
"Highlight the source code according to the measured coverage."
|
||||
],
|
||||
"Url" : "https://www.qt.io",
|
||||
"DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-coco.html",
|
||||
|
@@ -5,14 +5,57 @@ QtcPlugin {
|
||||
|
||||
Depends { name: "Core" }
|
||||
Depends { name: "LanguageClient" }
|
||||
Depends { name: "CMakeProjectManager" }
|
||||
Depends { name: "ExtensionSystem" }
|
||||
Depends { name: "ProjectExplorer" }
|
||||
Depends { name: "QmakeProjectManager" }
|
||||
Depends { name: "TextEditor" }
|
||||
Depends { name: "Utils" }
|
||||
|
||||
Depends { name: "Qt"; submodules: ["widgets"] }
|
||||
|
||||
files: [
|
||||
"cocoplugin.cpp",
|
||||
"cocobuild/buildsettings.cpp",
|
||||
"cocobuild/buildsettings.h",
|
||||
"cocobuild/cmakemodificationfile.cpp",
|
||||
"cocobuild/cmakemodificationfile.h",
|
||||
"cocobuild/cocobuildstep.cpp",
|
||||
"cocobuild/cocobuildstep.h",
|
||||
"cocobuild/cococmakesettings.cpp",
|
||||
"cocobuild/cococmakesettings.h",
|
||||
"cocobuild/cocoprojectwidget.cpp",
|
||||
"cocobuild/cocoprojectwidget.h",
|
||||
"cocobuild/cocoprojectwidget.ui",
|
||||
"cocobuild/cocoqmakesettings.cpp",
|
||||
"cocobuild/cocoqmakesettings.h",
|
||||
"cocobuild/modificationfile.cpp",
|
||||
"cocobuild/modificationfile.h",
|
||||
"cocobuild/qmakefeaturefile.cpp",
|
||||
"cocobuild/qmakefeaturefile.h",
|
||||
"cocolanguageclient.cpp",
|
||||
"cocolanguageclient.h",
|
||||
"cocoplugin.cpp",
|
||||
"cocoplugin.qrc",
|
||||
"cocoplugin_global.h",
|
||||
"cocopluginconstants.h",
|
||||
"cocotr.h",
|
||||
"common.cpp",
|
||||
"common.h",
|
||||
"files/cocoplugin-clang.cmake",
|
||||
"files/cocoplugin-gcc.cmake",
|
||||
"files/cocoplugin-visualstudio.cmake",
|
||||
"files/cocoplugin.cmake",
|
||||
"files/cocoplugin.prf",
|
||||
"images/SquishCoco_48x48.png",
|
||||
"settings/cocoinstallation.cpp",
|
||||
"settings/cocoinstallation.h",
|
||||
"settings/cocoprojectsettingswidget.cpp",
|
||||
"settings/cocoprojectsettingswidget.h",
|
||||
"settings/globalsettings.cpp",
|
||||
"settings/globalsettings.h",
|
||||
"settings/globalsettingspage.cpp",
|
||||
"settings/globalsettingspage.h",
|
||||
"settings/globalsettingspage.ui",
|
||||
]
|
||||
}
|
||||
|
||||
|
100
src/plugins/coco/cocobuild/buildsettings.cpp
Normal file
100
src/plugins/coco/cocobuild/buildsettings.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "buildsettings.h"
|
||||
|
||||
#include "cocobuildstep.h"
|
||||
#include "cococmakesettings.h"
|
||||
#include "cocoqmakesettings.h"
|
||||
#include "modificationfile.h"
|
||||
|
||||
#include <projectexplorer/target.h>
|
||||
#include <cmakeprojectmanager/cmakeprojectconstants.h>
|
||||
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
bool BuildSettings::supportsBuildConfig(const ProjectExplorer::BuildConfiguration &config)
|
||||
{
|
||||
return config.id() == QmakeProjectManager::Constants::QMAKE_BC_ID
|
||||
|| config.id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID;
|
||||
}
|
||||
|
||||
BuildSettings *BuildSettings::createdFor(const ProjectExplorer::BuildConfiguration &config)
|
||||
{
|
||||
if (config.id() == QmakeProjectManager::Constants::QMAKE_BC_ID)
|
||||
return new CocoQMakeSettings{config.project()};
|
||||
else if (config.id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID)
|
||||
return new CocoCMakeSettings{config.project()};
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BuildSettings::BuildSettings(ModificationFile &featureFile, ProjectExplorer::Project *project)
|
||||
: m_featureFile{featureFile}
|
||||
, m_project{*project}
|
||||
{
|
||||
// Do not use m_featureFile in the constructor; it may not yet be valid.
|
||||
}
|
||||
|
||||
void BuildSettings::connectToBuildStep(CocoBuildStep *step) const
|
||||
{
|
||||
connect(
|
||||
activeTarget(),
|
||||
&ProjectExplorer::Target::buildSystemUpdated,
|
||||
step,
|
||||
&CocoBuildStep::buildSystemUpdated);
|
||||
}
|
||||
|
||||
bool BuildSettings::enabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
const QStringList &BuildSettings::options() const
|
||||
{
|
||||
return m_featureFile.options();
|
||||
}
|
||||
|
||||
const QStringList &BuildSettings::tweaks() const
|
||||
{
|
||||
return m_featureFile.tweaks();
|
||||
}
|
||||
|
||||
bool BuildSettings::hasTweaks() const
|
||||
{
|
||||
return !m_featureFile.tweaks().isEmpty();
|
||||
}
|
||||
|
||||
QString BuildSettings::featureFilenName() const
|
||||
{
|
||||
return m_featureFile.fileName();
|
||||
}
|
||||
|
||||
QString BuildSettings::featureFilePath() const
|
||||
{
|
||||
return m_featureFile.nativePath();
|
||||
}
|
||||
|
||||
void BuildSettings::provideFile()
|
||||
{
|
||||
if (!m_featureFile.exists())
|
||||
write("", "");
|
||||
}
|
||||
|
||||
QString BuildSettings::tableRow(const QString &name, const QString &value) const
|
||||
{
|
||||
return QString("<tr><td><b>%1</b></td><td>%2</td></tr>").arg(name, value);
|
||||
}
|
||||
|
||||
void BuildSettings::setEnabled(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
ProjectExplorer::Target *BuildSettings::activeTarget() const
|
||||
{
|
||||
return m_project.activeTarget();
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
67
src/plugins/coco/cocobuild/buildsettings.h
Normal file
67
src/plugins/coco/cocobuild/buildsettings.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class BuildConfiguration;
|
||||
class Project;
|
||||
class Target;
|
||||
}
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class CocoBuildStep;
|
||||
class CocoProjectWidget;
|
||||
class ModificationFile;
|
||||
|
||||
class BuildSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static bool supportsBuildConfig(const ProjectExplorer::BuildConfiguration &config);
|
||||
static BuildSettings *createdFor(const ProjectExplorer::BuildConfiguration &config);
|
||||
|
||||
explicit BuildSettings(ModificationFile &featureFile, ProjectExplorer::Project *project);
|
||||
virtual ~BuildSettings() {}
|
||||
|
||||
void connectToBuildStep(CocoBuildStep *step) const;
|
||||
virtual void connectToProject(CocoProjectWidget *) const {}
|
||||
virtual void read() = 0;
|
||||
bool enabled() const;
|
||||
virtual bool validSettings() const = 0;
|
||||
virtual void setCoverage(bool on) = 0;
|
||||
|
||||
virtual QString saveButtonText() const = 0;
|
||||
virtual void reconfigure() {};
|
||||
virtual void stopReconfigure() {};
|
||||
virtual bool needsReconfigure() const { return false; }
|
||||
|
||||
virtual QString configChanges() const = 0;
|
||||
|
||||
const QStringList &options() const;
|
||||
const QStringList &tweaks() const;
|
||||
virtual QString projectDirectory() const = 0;
|
||||
|
||||
bool hasTweaks() const;
|
||||
QString featureFilenName() const;
|
||||
QString featureFilePath() const;
|
||||
|
||||
virtual void write(const QString &options, const QString &tweaks) = 0;
|
||||
void provideFile();
|
||||
|
||||
protected:
|
||||
QString tableRow(const QString &name, const QString &value) const;
|
||||
void setEnabled(bool enabled);
|
||||
ProjectExplorer::Target *activeTarget() const;
|
||||
|
||||
private:
|
||||
ModificationFile &m_featureFile;
|
||||
ProjectExplorer::Project &m_project;
|
||||
bool m_enabled = false;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
91
src/plugins/coco/cocobuild/cmakemodificationfile.cpp
Normal file
91
src/plugins/coco/cocobuild/cmakemodificationfile.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cmakemodificationfile.h"
|
||||
|
||||
#include "cocopluginconstants.h"
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
static const char flagsSetting[] = "set(coverage_flags_list\n";
|
||||
static const char tweaksLine[] = "# User-supplied settings follow here:\n";
|
||||
|
||||
CMakeModificationFile::CMakeModificationFile(Project *project)
|
||||
: m_project{project}
|
||||
{}
|
||||
|
||||
QString CMakeModificationFile::fileName() const
|
||||
{
|
||||
return QString(Constants::PROFILE_NAME) + ".cmake";
|
||||
}
|
||||
|
||||
void CMakeModificationFile::setProjectDirectory(const Utils::FilePath &projectDirectory)
|
||||
{
|
||||
setFilePath(projectDirectory.pathAppended(fileName()));
|
||||
}
|
||||
|
||||
QStringList CMakeModificationFile::defaultModificationFile() const
|
||||
{
|
||||
return contentOf(":/cocoplugin/files/cocoplugin.cmake");
|
||||
}
|
||||
|
||||
void CMakeModificationFile::read()
|
||||
{
|
||||
clear();
|
||||
QStringList file = currentModificationFile();
|
||||
|
||||
{
|
||||
QStringList options;
|
||||
int i = file.indexOf(flagsSetting);
|
||||
if (i != -1) {
|
||||
i++;
|
||||
while (i < file.size() && !file[i].startsWith(')')) {
|
||||
options += file[i].trimmed();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
setOptions(options);
|
||||
}
|
||||
{
|
||||
QStringList tweaks;
|
||||
int i = file.indexOf(tweaksLine);
|
||||
if (i != -1) {
|
||||
i++;
|
||||
while (i < file.size()) {
|
||||
tweaks += file[i].chopped(1);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
setTweaks(tweaks);
|
||||
}
|
||||
}
|
||||
|
||||
void CMakeModificationFile::write() const
|
||||
{
|
||||
QFile out(nativePath());
|
||||
out.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||
|
||||
QTextStream outStream(&out);
|
||||
for (QString &line : defaultModificationFile()) {
|
||||
outStream << line;
|
||||
|
||||
if (line.startsWith(flagsSetting)) {
|
||||
for (const QString &option : options()) {
|
||||
QString line = " " + option + '\n';
|
||||
outStream << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const QString &line : tweaks())
|
||||
outStream << line << "\n";
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
32
src/plugins/coco/cocobuild/cmakemodificationfile.h
Normal file
32
src/plugins/coco/cocobuild/cmakemodificationfile.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "modificationfile.h"
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Project;
|
||||
}
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class CMakeModificationFile : public ModificationFile
|
||||
{
|
||||
public:
|
||||
CMakeModificationFile(ProjectExplorer::Project *project);
|
||||
|
||||
void read() override;
|
||||
void write() const override;
|
||||
|
||||
QString fileName() const override;
|
||||
void setProjectDirectory(const Utils::FilePath &projectDirectory) override;
|
||||
|
||||
protected:
|
||||
QStringList defaultModificationFile() const override;
|
||||
|
||||
private:
|
||||
ProjectExplorer::Project *m_project;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
126
src/plugins/coco/cocobuild/cocobuildstep.cpp
Normal file
126
src/plugins/coco/cocobuild/cocobuildstep.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cocobuildstep.h"
|
||||
|
||||
#include "cocopluginconstants.h"
|
||||
#include "cocotr.h"
|
||||
|
||||
#include <cmakeprojectmanager/cmakeprojectconstants.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <settings/cocoinstallation.h>
|
||||
#include <settings/globalsettingspage.h>
|
||||
#include <solutions/tasking/tasktree.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
QMakeStepFactory::QMakeStepFactory()
|
||||
{
|
||||
registerStep<CocoBuildStep>(Utils::Id{Constants::COCO_STEP_ID});
|
||||
setSupportedProjectType(QmakeProjectManager::Constants::QMAKEPROJECT_ID);
|
||||
setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
|
||||
setRepeatable(false);
|
||||
}
|
||||
|
||||
CMakeStepFactory::CMakeStepFactory()
|
||||
{
|
||||
registerStep<CocoBuildStep>(Utils::Id{Constants::COCO_STEP_ID});
|
||||
setSupportedProjectType(CMakeProjectManager::Constants::CMAKE_PROJECT_ID);
|
||||
setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
|
||||
setRepeatable(false);
|
||||
}
|
||||
|
||||
CocoBuildStep *CocoBuildStep::create(BuildConfiguration *buildConfig)
|
||||
{
|
||||
// The "new" command creates a small memory leak which we can tolerate.
|
||||
return new CocoBuildStep(
|
||||
new BuildStepList(buildConfig, Constants::COCO_STEP_ID), Utils::Id(Constants::COCO_STEP_ID));
|
||||
}
|
||||
|
||||
CocoBuildStep::CocoBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id)
|
||||
: BuildStep(bsl, id)
|
||||
, m_reconfigureButton{new QPushButton}
|
||||
{}
|
||||
|
||||
bool CocoBuildStep::init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CocoBuildStep::buildSystemUpdated()
|
||||
{
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
void CocoBuildStep::onReconfigureButtonClicked()
|
||||
{
|
||||
m_valid = !m_valid;
|
||||
|
||||
setSummaryText(Tr::tr("Coco Code Coverage: Reconfiguring..."));
|
||||
m_reconfigureButton->setEnabled(false);
|
||||
m_buildSettings->setCoverage(m_valid);
|
||||
m_buildSettings->provideFile();
|
||||
m_buildSettings->reconfigure();
|
||||
}
|
||||
|
||||
QWidget *CocoBuildStep::createConfigWidget()
|
||||
{
|
||||
connect(
|
||||
m_reconfigureButton,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&CocoBuildStep::onReconfigureButtonClicked);
|
||||
|
||||
Layouting::Form builder;
|
||||
builder.addRow({m_reconfigureButton, new QLabel});
|
||||
builder.setNoMargins();
|
||||
|
||||
return builder.emerge();
|
||||
}
|
||||
|
||||
void CocoBuildStep::updateDisplay()
|
||||
{
|
||||
CocoInstallation coco;
|
||||
if (!coco.isValid()) {
|
||||
setSummaryText("<i>" + Tr::tr("Coco Code Coverage: No working Coco installation") + "</i>");
|
||||
m_reconfigureButton->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
m_valid = m_buildSettings->validSettings();
|
||||
|
||||
if (m_valid) {
|
||||
setSummaryText("<b>" + Tr::tr("Coco Code Coverage: Enabled") + "</b>");
|
||||
m_reconfigureButton->setText(Tr::tr("Disable Coverage"));
|
||||
} else {
|
||||
setSummaryText(Tr::tr("Coco Code Coverage: Disabled"));
|
||||
m_reconfigureButton->setText(Tr::tr("Enable Coverage"));
|
||||
}
|
||||
|
||||
m_reconfigureButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void CocoBuildStep::display(BuildConfiguration *buildConfig)
|
||||
{
|
||||
Q_ASSERT( m_buildSettings.isNull() );
|
||||
|
||||
m_buildSettings = BuildSettings::createdFor(*buildConfig);
|
||||
m_buildSettings->read();
|
||||
m_buildSettings->connectToBuildStep(this);
|
||||
|
||||
setImmutable(true);
|
||||
updateDisplay();
|
||||
}
|
||||
|
||||
Tasking::GroupItem CocoBuildStep::runRecipe()
|
||||
{
|
||||
return Tasking::GroupItem({});
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
59
src/plugins/coco/cocobuild/cocobuildstep.h
Normal file
59
src/plugins/coco/cocobuild/cocobuildstep.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "buildsettings.h"
|
||||
|
||||
#include <projectexplorer/buildstep.h>
|
||||
#include <projectexplorer/buildsteplist.h>
|
||||
#include <projectexplorer/project.h>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
class QPushButton;
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class QMakeStepFactory: public ProjectExplorer::BuildStepFactory
|
||||
{
|
||||
public:
|
||||
QMakeStepFactory();
|
||||
};
|
||||
|
||||
class CMakeStepFactory: public ProjectExplorer::BuildStepFactory
|
||||
{
|
||||
public:
|
||||
CMakeStepFactory();
|
||||
};
|
||||
|
||||
class CocoBuildStep : public ProjectExplorer::BuildStep
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static CocoBuildStep *create(ProjectExplorer::BuildConfiguration *buildConfig);
|
||||
|
||||
CocoBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id);
|
||||
|
||||
bool init() override;
|
||||
void display(ProjectExplorer::BuildConfiguration *buildConfig);
|
||||
|
||||
public slots:
|
||||
void buildSystemUpdated();
|
||||
|
||||
private slots:
|
||||
void onReconfigureButtonClicked();
|
||||
|
||||
protected:
|
||||
QWidget *createConfigWidget() override;
|
||||
|
||||
private:
|
||||
void updateDisplay();
|
||||
Tasking::GroupItem runRecipe() override;
|
||||
|
||||
QPointer<BuildSettings> m_buildSettings;
|
||||
bool m_valid;
|
||||
QPushButton *m_reconfigureButton;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
167
src/plugins/coco/cocobuild/cococmakesettings.cpp
Normal file
167
src/plugins/coco/cocobuild/cococmakesettings.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cococmakesettings.h"
|
||||
|
||||
#include "cocobuild/cocoprojectwidget.h"
|
||||
#include "cocotr.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <cmakeprojectmanager/cmakebuildconfiguration.h>
|
||||
#include <cmakeprojectmanager/cmakebuildsystem.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace CMakeProjectManager;
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
CocoCMakeSettings::CocoCMakeSettings(Project *project)
|
||||
: BuildSettings{m_featureFile, project}
|
||||
, m_featureFile{project}
|
||||
{}
|
||||
|
||||
CocoCMakeSettings::~CocoCMakeSettings() {}
|
||||
|
||||
void CocoCMakeSettings::connectToProject(CocoProjectWidget *parent) const
|
||||
{
|
||||
connect(
|
||||
activeTarget(), &Target::buildSystemUpdated, parent, &CocoProjectWidget::buildSystemUpdated);
|
||||
connect(
|
||||
qobject_cast<CMakeProjectManager::CMakeBuildSystem *>(activeTarget()->buildSystem()),
|
||||
&CMakeProjectManager::CMakeBuildSystem::errorOccurred,
|
||||
parent,
|
||||
&CocoProjectWidget::configurationErrorOccurred);
|
||||
}
|
||||
|
||||
void CocoCMakeSettings::read()
|
||||
{
|
||||
setEnabled(false);
|
||||
if (Target *target = activeTarget()) {
|
||||
if ((m_buildConfig = qobject_cast<CMakeBuildConfiguration *>(
|
||||
target->activeBuildConfiguration()))) {
|
||||
m_featureFile.setProjectDirectory(m_buildConfig->project()->projectDirectory());
|
||||
m_featureFile.read();
|
||||
setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString CocoCMakeSettings::initialCacheOption() const
|
||||
{
|
||||
return QString("-C%1").arg(m_featureFile.nativePath());
|
||||
}
|
||||
|
||||
bool CocoCMakeSettings::hasInitialCacheOption(const QStringList &args) const
|
||||
{
|
||||
for (int i = 0; i < args.length(); ++i) {
|
||||
if (args[i] == "-C" && i + 1 < args.length() && args[i + 1] == m_featureFile.nativePath())
|
||||
return true;
|
||||
|
||||
if (args[i] == initialCacheOption())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CocoCMakeSettings::validSettings() const
|
||||
{
|
||||
return enabled() && m_featureFile.exists()
|
||||
&& hasInitialCacheOption(m_buildConfig->additionalCMakeArguments());
|
||||
}
|
||||
|
||||
void CocoCMakeSettings::setCoverage(bool on)
|
||||
{
|
||||
if (!enabled())
|
||||
return;
|
||||
|
||||
auto values = m_buildConfig->initialCMakeOptions();
|
||||
QStringList args = Utils::filtered(values, [&](const QString &option) {
|
||||
return !(option.startsWith("-C") && option.endsWith(featureFilenName()));
|
||||
});
|
||||
|
||||
if (on)
|
||||
args << QString("-C%1").arg(m_featureFile.nativePath());
|
||||
|
||||
m_buildConfig->setInitialCMakeArguments(args);
|
||||
}
|
||||
|
||||
QString CocoCMakeSettings::saveButtonText() const
|
||||
{
|
||||
return Tr::tr("Save && Re-configure");
|
||||
}
|
||||
|
||||
QString CocoCMakeSettings::configChanges() const
|
||||
{
|
||||
return "<table><tbody>"
|
||||
+ tableRow("Additional CMake options: ", maybeQuote(initialCacheOption()))
|
||||
+ tableRow("Initial cache script: ", maybeQuote(featureFilePath())) + "</tbody></table>";
|
||||
}
|
||||
|
||||
void CocoCMakeSettings::reconfigure()
|
||||
{
|
||||
if (!enabled())
|
||||
return;
|
||||
|
||||
m_buildConfig->cmakeBuildSystem()->clearCMakeCache();
|
||||
m_buildConfig->updateInitialCMakeArguments();
|
||||
m_buildConfig->cmakeBuildSystem()->runCMake();
|
||||
}
|
||||
|
||||
void Coco::Internal::CocoCMakeSettings::stopReconfigure()
|
||||
{
|
||||
if (enabled())
|
||||
m_buildConfig->cmakeBuildSystem()->stopCMakeRun();
|
||||
}
|
||||
|
||||
QString CocoCMakeSettings::projectDirectory() const
|
||||
{
|
||||
if (enabled())
|
||||
return m_buildConfig->project()->projectDirectory().path();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
void CocoCMakeSettings::write(const QString &options, const QString &tweaks)
|
||||
{
|
||||
m_featureFile.setOptions(options);
|
||||
m_featureFile.setTweaks(tweaks);
|
||||
m_featureFile.write();
|
||||
|
||||
writeToolchainFile(":/cocoplugin/files/cocoplugin-gcc.cmake");
|
||||
writeToolchainFile(":/cocoplugin/files/cocoplugin-clang.cmake");
|
||||
writeToolchainFile(":/cocoplugin/files/cocoplugin-visualstudio.cmake");
|
||||
}
|
||||
|
||||
void CocoCMakeSettings::writeToolchainFile(const QString &internalPath)
|
||||
{
|
||||
const Utils::FilePath projectDirectory = m_buildConfig->project()->projectDirectory();
|
||||
|
||||
QFile internalFile{internalPath};
|
||||
internalFile.open(QIODeviceBase::ReadOnly);
|
||||
const QByteArray internalContent = internalFile.readAll();
|
||||
|
||||
const QString fileName = Utils::FilePath::fromString(internalPath).fileName();
|
||||
const Utils::FilePath toolchainPath{projectDirectory.pathAppended(fileName)};
|
||||
const QString toolchainNative = toolchainPath.nativePath();
|
||||
|
||||
if (toolchainPath.exists()) {
|
||||
QFile currentFile{toolchainNative};
|
||||
currentFile.open(QIODeviceBase::ReadOnly);
|
||||
|
||||
QByteArray currentContent = currentFile.readAll();
|
||||
if (internalContent == currentContent)
|
||||
return;
|
||||
|
||||
logSilently(Tr::tr("Overwrite file %1").arg(maybeQuote(toolchainNative)));
|
||||
} else
|
||||
logSilently(Tr::tr("Write file %1").arg(maybeQuote(toolchainNative)));
|
||||
|
||||
QFile out{toolchainNative};
|
||||
out.open(QIODeviceBase::WriteOnly);
|
||||
out.write(internalContent);
|
||||
out.close();
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
51
src/plugins/coco/cocobuild/cococmakesettings.h
Normal file
51
src/plugins/coco/cocobuild/cococmakesettings.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cocobuild/buildsettings.h"
|
||||
#include "cocobuild/cmakemodificationfile.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
namespace CMakeProjectManager {
|
||||
class CMakeBuildConfiguration;
|
||||
class CMakeConfig;
|
||||
}
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class CocoProjectWidget;
|
||||
|
||||
class CocoCMakeSettings : public BuildSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CocoCMakeSettings(ProjectExplorer::Project *project);
|
||||
~CocoCMakeSettings() override;
|
||||
|
||||
void connectToProject(CocoProjectWidget *parent) const override;
|
||||
void read() override;
|
||||
bool validSettings() const override;
|
||||
void setCoverage(bool on) override;
|
||||
|
||||
QString saveButtonText() const override;
|
||||
QString configChanges() const override;
|
||||
bool needsReconfigure() const override { return true; }
|
||||
void reconfigure() override;
|
||||
void stopReconfigure() override;
|
||||
|
||||
QString projectDirectory() const override;
|
||||
void write(const QString &options, const QString &tweaks) override;
|
||||
|
||||
private:
|
||||
bool hasInitialCacheOption(const QStringList &args) const;
|
||||
QString initialCacheOption() const;
|
||||
void writeToolchainFile(const QString &internalPath);
|
||||
|
||||
CMakeProjectManager::CMakeBuildConfiguration *m_buildConfig;
|
||||
CMakeModificationFile m_featureFile;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
336
src/plugins/coco/cocobuild/cocoprojectwidget.cpp
Normal file
336
src/plugins/coco/cocobuild/cocoprojectwidget.cpp
Normal file
@@ -0,0 +1,336 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cocoprojectwidget.h"
|
||||
|
||||
#include "buildsettings.h"
|
||||
#include "cocopluginconstants.h"
|
||||
#include "cocotr.h"
|
||||
#include "common.h"
|
||||
#include "settings/globalsettingspage.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <projectexplorer/buildsystem.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Core;
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
CocoProjectWidget::CocoProjectWidget(Project *project, const BuildConfiguration &buildConfig)
|
||||
: m_project{project}
|
||||
, m_buildConfigurationName{buildConfig.displayName()}
|
||||
{
|
||||
using namespace Layouting;
|
||||
using namespace Utils;
|
||||
|
||||
m_configerrorLabel.setVisible(false);
|
||||
m_configerrorLabel.setIconType(InfoLabel::Error);
|
||||
Label docLink(
|
||||
QString(
|
||||
"<a href=\"https://doc.qt.io/coco/coveragescanner-command-line-arguments.html\">%1</a>")
|
||||
.arg(Tr::tr("Documentation")));
|
||||
docLink.setOpenExternalLinks(true);
|
||||
m_optionEdit.setDisplayStyle(StringAspect::TextEditDisplay);
|
||||
m_tweaksEdit.setDisplayStyle(StringAspect::TextEditDisplay);
|
||||
m_revertButton.setText(Tr::tr("Revert"));
|
||||
QFont bold;
|
||||
bold.setBold(true);
|
||||
m_saveButton.setFont(bold);
|
||||
|
||||
m_coverageGroupbox
|
||||
= {groupChecker(m_coverageGroupBoxEnabled.groupChecker()),
|
||||
Column{
|
||||
Row{Tr::tr("CoverageScanner Options"), st, docLink},
|
||||
m_optionEdit,
|
||||
Row{PushButton{
|
||||
text(Tr::tr("Exclude File...")),
|
||||
onClicked([&] { onExcludeFileButtonClicked(); }, this)},
|
||||
PushButton{
|
||||
text(Tr::tr("Exclude Directory...")),
|
||||
onClicked([&] { onExcludeDirButtonClicked(); }, this)},
|
||||
m_tweaksButton,
|
||||
st},
|
||||
m_tweaksDescriptionLabel,
|
||||
m_tweaksEdit,
|
||||
Row{Tr::tr("These settings are stored in"), m_fileNameLabel, st},
|
||||
Group{title(Tr::tr("Changed Build Settings")), Column{m_changesText}}}};
|
||||
|
||||
Column{
|
||||
m_configerrorLabel,
|
||||
m_coverageGroupbox,
|
||||
Row{m_messageLabel, st, &m_revertButton, &m_saveButton}}
|
||||
.attachTo(this);
|
||||
|
||||
m_buildSettings = BuildSettings::createdFor(buildConfig);
|
||||
m_buildSettings->connectToProject(this);
|
||||
|
||||
readSelectionDir();
|
||||
reloadSettings();
|
||||
|
||||
m_fileNameLabel.setValue(m_buildSettings->featureFilePath());
|
||||
m_tweaksDescriptionLabel.setText(
|
||||
Tr::tr("Code for the end of the file \"%1\" to override the built-in declarations."
|
||||
" Only needed in special cases.")
|
||||
.arg(m_buildSettings->featureFilenName()));
|
||||
setTweaksVisible(m_buildSettings->hasTweaks());
|
||||
clearMessageLabel();
|
||||
|
||||
connect(&m_coverageGroupBoxEnabled, &BoolAspect::changed, this, &CocoProjectWidget::onCoverageGroupBoxClicked);
|
||||
|
||||
connect(&m_optionEdit, &StringAspect::changed, this, &CocoProjectWidget::onTextChanged);
|
||||
connect(&m_tweaksEdit, &StringAspect::changed, this, &CocoProjectWidget::onTextChanged);
|
||||
m_tweaksButton.onClicked([&] { onTweaksButtonClicked(); }, this);
|
||||
|
||||
connect(&m_revertButton, &QPushButton::clicked, this, &CocoProjectWidget::onRevertButtonClicked);
|
||||
connect(&m_saveButton, &QPushButton::clicked, this, &CocoProjectWidget::onSaveButtonClicked);
|
||||
|
||||
connect(GlobalSettingsPage::instance().widget(), &GlobalSettingsWidget::updateCocoDir, this, &CocoProjectWidget::reloadSettings);
|
||||
}
|
||||
|
||||
// Read the build settings again and show them in the widget.
|
||||
void CocoProjectWidget::reloadSettings()
|
||||
{
|
||||
m_buildSettings->read();
|
||||
m_coverageGroupBoxEnabled.setValue(m_buildSettings->validSettings(), Utils::BaseAspect::BeQuiet);
|
||||
m_coverageGroupbox.setTitle(
|
||||
Tr::tr("Enable code coverage for build configuration \"%1\"").arg(m_buildConfigurationName));
|
||||
|
||||
m_optionEdit.setValue(m_buildSettings->options().join('\n'), Utils::BaseAspect::BeQuiet);
|
||||
m_tweaksEdit.setValue(m_buildSettings->tweaks().join('\n'), Utils::BaseAspect::BeQuiet);
|
||||
|
||||
setState(configDone);
|
||||
displayChanges();
|
||||
|
||||
const bool valid = m_coco.isValid();
|
||||
m_configerrorLabel.setVisible(!valid);
|
||||
if (!valid) {
|
||||
m_configerrorLabel.setText(
|
||||
Tr::tr("Coco is not installed correctly: \"%1\"").arg(m_coco.errorMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
void CocoProjectWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
reloadSettings();
|
||||
}
|
||||
|
||||
void CocoProjectWidget::buildSystemUpdated(ProjectExplorer::BuildSystem *bs)
|
||||
{
|
||||
QString newBuildConfigurationName = bs->buildConfiguration()->displayName();
|
||||
|
||||
if (m_buildConfigurationName != newBuildConfigurationName) {
|
||||
m_buildConfigurationName = newBuildConfigurationName;
|
||||
logSilently(Tr::tr("Build Configuration changed to %1.").arg(newBuildConfigurationName));
|
||||
reloadSettings();
|
||||
} else if (m_configState == configRunning)
|
||||
setState(configDone);
|
||||
}
|
||||
|
||||
void CocoProjectWidget::configurationErrorOccurred(const QString &error)
|
||||
{
|
||||
Q_UNUSED(error)
|
||||
|
||||
if (m_configState == configEdited) {
|
||||
setMessageLabel(Utils::InfoLabel::Information, Tr::tr("Re-configuring stopped by user."));
|
||||
setState(configStopped);
|
||||
} else {
|
||||
// The variable error seems to contain no usable information.
|
||||
setMessageLabel(
|
||||
Utils::InfoLabel::Error,
|
||||
Tr::tr("Error when configuring with \"%1\". "
|
||||
"Check General Messages for more information.")
|
||||
.arg(m_buildSettings->featureFilenName()));
|
||||
setState(configDone);
|
||||
}
|
||||
}
|
||||
|
||||
void CocoProjectWidget::setState(ConfigurationState state)
|
||||
{
|
||||
m_configState = state;
|
||||
|
||||
switch (m_configState) {
|
||||
case configDone:
|
||||
m_saveButton.setText(m_buildSettings->saveButtonText());
|
||||
m_saveButton.setEnabled(false);
|
||||
m_revertButton.setEnabled(false);
|
||||
break;
|
||||
case configEdited:
|
||||
m_saveButton.setText(m_buildSettings->saveButtonText());
|
||||
m_saveButton.setEnabled(true);
|
||||
m_revertButton.setEnabled(true);
|
||||
break;
|
||||
case configRunning:
|
||||
m_saveButton.setText(Tr::tr("Stop Re-configuring"));
|
||||
m_saveButton.setEnabled(true);
|
||||
m_revertButton.setEnabled(false);
|
||||
break;
|
||||
case configStopped:
|
||||
m_saveButton.setText(Tr::tr("Re-configure"));
|
||||
m_saveButton.setEnabled(true);
|
||||
m_revertButton.setEnabled(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CocoProjectWidget::readSelectionDir()
|
||||
{
|
||||
QVariantMap settings = m_project->namedSettings(Constants::SETTINGS_NAME_KEY).toMap();
|
||||
|
||||
if (settings.contains(Constants::SELECTION_DIR_KEY))
|
||||
m_selectionDirectory = settings[Constants::SELECTION_DIR_KEY].toString();
|
||||
else
|
||||
m_selectionDirectory = m_buildSettings->projectDirectory();
|
||||
}
|
||||
|
||||
void CocoProjectWidget::writeSelectionDir(const QString &path)
|
||||
{
|
||||
m_selectionDirectory = path;
|
||||
|
||||
QVariantMap settings;
|
||||
settings[Constants::SELECTION_DIR_KEY] = path;
|
||||
|
||||
m_project->setNamedSettings(Constants::SETTINGS_NAME_KEY, settings);
|
||||
}
|
||||
|
||||
void CocoProjectWidget::setTweaksVisible(bool on)
|
||||
{
|
||||
if (on)
|
||||
m_tweaksButton.setText(Tr::tr("Override <<"));
|
||||
else
|
||||
m_tweaksButton.setText(Tr::tr("Override >>"));
|
||||
|
||||
m_tweaksDescriptionLabel.setVisible(on);
|
||||
m_tweaksEdit.setVisible(on);
|
||||
}
|
||||
|
||||
void CocoProjectWidget::setMessageLabel(const Utils::InfoLabel::InfoType type, const QString &text)
|
||||
{
|
||||
m_messageLabel.setText(text);
|
||||
m_messageLabel.setIconType(type);
|
||||
}
|
||||
|
||||
void CocoProjectWidget::clearMessageLabel()
|
||||
{
|
||||
m_messageLabel.setText("");
|
||||
m_messageLabel.setIconType(Utils::InfoLabel::None);
|
||||
}
|
||||
|
||||
void Internal::CocoProjectWidget::onCoverageGroupBoxClicked()
|
||||
{
|
||||
bool checked = m_coverageGroupBoxEnabled();
|
||||
|
||||
displayChanges();
|
||||
|
||||
if (!checked) {
|
||||
m_buildSettings->setCoverage(false);
|
||||
setState(configEdited);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_coco.isValid()) {
|
||||
m_coverageGroupBoxEnabled.setValue(false, Utils::BaseAspect::BeQuiet);
|
||||
|
||||
QMessageBox box;
|
||||
box.setIcon(QMessageBox::Critical);
|
||||
box.setText(Tr::tr("The Coco installation path is not set correctly."));
|
||||
box.addButton(QMessageBox::Cancel);
|
||||
QPushButton *editButton = box.addButton(Tr::tr("Edit"), QMessageBox::AcceptRole);
|
||||
box.exec();
|
||||
|
||||
if (box.clickedButton() == editButton)
|
||||
Core::ICore::showOptionsDialog(Constants::COCO_SETTINGS_PAGE_ID);
|
||||
|
||||
m_coverageGroupBoxEnabled.setValue(m_coco.isValid(), Utils::BaseAspect::BeQuiet);
|
||||
} else
|
||||
m_buildSettings->setCoverage(checked);
|
||||
|
||||
setState(configEdited);
|
||||
}
|
||||
|
||||
void CocoProjectWidget::onSaveButtonClicked()
|
||||
{
|
||||
if (m_configState == configRunning) {
|
||||
logSilently(Tr::tr("Stop re-configuring"));
|
||||
m_buildSettings->stopReconfigure();
|
||||
setState(configEdited);
|
||||
return;
|
||||
}
|
||||
|
||||
QString options = m_optionEdit();
|
||||
QString tweaks = m_tweaksEdit();
|
||||
clearMessageLabel();
|
||||
|
||||
logSilently(Tr::tr("Write file \"%1\"").arg(m_buildSettings->featureFilePath()));
|
||||
m_buildSettings->write(options, tweaks);
|
||||
|
||||
if (m_buildSettings->needsReconfigure()) {
|
||||
logSilently(Tr::tr("Re-configure"));
|
||||
setState(configRunning);
|
||||
m_buildSettings->reconfigure();
|
||||
} else
|
||||
setState(configDone);
|
||||
}
|
||||
|
||||
void CocoProjectWidget::onRevertButtonClicked()
|
||||
{
|
||||
clearMessageLabel();
|
||||
logSilently(Tr::tr("Reload file \"%1\"").arg(m_buildSettings->featureFilePath()));
|
||||
reloadSettings();
|
||||
}
|
||||
|
||||
void CocoProjectWidget::onTextChanged()
|
||||
{
|
||||
setState(configEdited);
|
||||
}
|
||||
|
||||
void CocoProjectWidget::displayChanges()
|
||||
{
|
||||
m_changesText.setValue(m_buildSettings->configChanges());
|
||||
}
|
||||
|
||||
void CocoProjectWidget::addCocoOption(QString option)
|
||||
{
|
||||
m_optionEdit.setValue(m_optionEdit() + "\n" + option);
|
||||
}
|
||||
|
||||
void CocoProjectWidget::onExcludeFileButtonClicked()
|
||||
{
|
||||
QString fileName = QFileDialog::getOpenFileName(
|
||||
this, Tr::tr("File to Exclude from Instrumentation"), m_selectionDirectory);
|
||||
if (fileName.isEmpty())
|
||||
return;
|
||||
|
||||
const auto fileNameInfo = Utils::FilePath::fromString(fileName);
|
||||
addCocoOption("--cs-exclude-file-abs-wildcard=" + maybeQuote("*/" + fileNameInfo.fileName()));
|
||||
|
||||
writeSelectionDir(fileNameInfo.path());
|
||||
}
|
||||
|
||||
void CocoProjectWidget::onExcludeDirButtonClicked()
|
||||
{
|
||||
QString path = QFileDialog::getExistingDirectory(
|
||||
this, Tr::tr("Directory to Exclude from Instrumentation"), m_selectionDirectory);
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
||||
const QString projectDir = m_buildSettings->projectDirectory();
|
||||
if (path.startsWith(projectDir))
|
||||
// Make it a relative path with "*/" at the beginnig.
|
||||
path = "*/" + path.arg(path.mid(projectDir.size()));
|
||||
|
||||
addCocoOption("--cs-exclude-file-abs-wildcard=" + maybeQuote(path));
|
||||
|
||||
writeSelectionDir(path);
|
||||
}
|
||||
|
||||
void Internal::CocoProjectWidget::onTweaksButtonClicked()
|
||||
{
|
||||
setTweaksVisible(!m_tweaksEdit.isVisible());
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
81
src/plugins/coco/cocobuild/cocoprojectwidget.h
Normal file
81
src/plugins/coco/cocobuild/cocoprojectwidget.h
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "buildsettings.h"
|
||||
#include "projectexplorer/buildconfiguration.h"
|
||||
#include "settings/cocoinstallation.h"
|
||||
#include <utils/aspects.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
#include <QPointer>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Project;
|
||||
}
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class CocoProjectWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ConfigurationState { configDone, configEdited, configRunning, configStopped };
|
||||
|
||||
explicit CocoProjectWidget(
|
||||
ProjectExplorer::Project *project, const ProjectExplorer::BuildConfiguration &buildConfig);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
public slots:
|
||||
void buildSystemUpdated(ProjectExplorer::BuildSystem *bs);
|
||||
void configurationErrorOccurred(const QString &error);
|
||||
|
||||
private slots:
|
||||
void onCoverageGroupBoxClicked();
|
||||
|
||||
void onSaveButtonClicked();
|
||||
void onRevertButtonClicked();
|
||||
void onExcludeFileButtonClicked();
|
||||
void onExcludeDirButtonClicked();
|
||||
void onTweaksButtonClicked();
|
||||
|
||||
void onTextChanged();
|
||||
|
||||
private:
|
||||
void displayChanges();
|
||||
void reloadSettings();
|
||||
void addCocoOption(QString option);
|
||||
void setState(ConfigurationState state);
|
||||
void readSelectionDir();
|
||||
void writeSelectionDir(const QString &path);
|
||||
void setTweaksVisible(bool on);
|
||||
void setMessageLabel(const Utils::InfoLabel::InfoType type, const QString &text);
|
||||
void clearMessageLabel();
|
||||
|
||||
Utils::TextDisplay m_configerrorLabel;
|
||||
Utils::BoolAspect m_coverageGroupBoxEnabled;
|
||||
Layouting::Group m_coverageGroupbox{};
|
||||
Utils::StringAspect m_optionEdit;
|
||||
Layouting::PushButton m_tweaksButton{};
|
||||
Utils::TextDisplay m_tweaksDescriptionLabel;
|
||||
Utils::StringAspect m_tweaksEdit;
|
||||
Utils::StringAspect m_fileNameLabel;
|
||||
Utils::TextDisplay m_messageLabel;
|
||||
QPushButton m_revertButton;
|
||||
QPushButton m_saveButton;
|
||||
Utils::StringAspect m_changesText;
|
||||
|
||||
ProjectExplorer::Project *m_project;
|
||||
QPointer<BuildSettings> m_buildSettings;
|
||||
QString m_selectionDirectory;
|
||||
ConfigurationState m_configState = configDone;
|
||||
QString m_buildConfigurationName;
|
||||
CocoInstallation m_coco;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
188
src/plugins/coco/cocobuild/cocoqmakesettings.cpp
Normal file
188
src/plugins/coco/cocobuild/cocoqmakesettings.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cocoqmakesettings.h"
|
||||
|
||||
#include "cocobuild/cocoprojectwidget.h"
|
||||
#include "cocopluginconstants.h"
|
||||
#include "cocotr.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <projectexplorer/buildsteplist.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <qmakeprojectmanager/qmakebuildconfiguration.h>
|
||||
#include <qmakeprojectmanager/qmakestep.h>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
CocoQMakeSettings::CocoQMakeSettings(Project *project)
|
||||
: BuildSettings{m_featureFile, project}
|
||||
{}
|
||||
|
||||
CocoQMakeSettings::~CocoQMakeSettings() {}
|
||||
|
||||
void CocoQMakeSettings::read()
|
||||
{
|
||||
setEnabled(false);
|
||||
if (Target *target = activeTarget()) {
|
||||
if ((m_buildConfig = qobject_cast<QmakeProjectManager::QmakeBuildConfiguration*>(target->activeBuildConfiguration()))) {
|
||||
if (BuildStepList *buildSteps = m_buildConfig->buildSteps()) {
|
||||
if ((m_qmakeStep = buildSteps->firstOfType<QmakeProjectManager::QMakeStep>())) {
|
||||
m_featureFile.setProjectDirectory(m_buildConfig->project()->projectDirectory());
|
||||
m_featureFile.read();
|
||||
setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString configAssignment()
|
||||
{
|
||||
static const QString assignment = QString("CONFIG+=") + Constants::PROFILE_NAME;
|
||||
return assignment;
|
||||
}
|
||||
|
||||
static const char pathAssignmentPrefix[] = "COCOPATH=";
|
||||
static const char featuresVar[] = "QMAKEFEATURES";
|
||||
|
||||
const QStringList CocoQMakeSettings::userArgumentList() const
|
||||
{
|
||||
if (!enabled())
|
||||
return {};
|
||||
|
||||
Utils::ProcessArgs::ConstArgIterator it{m_qmakeStep->userArguments.unexpandedArguments()};
|
||||
QStringList result;
|
||||
|
||||
while (it.next()) {
|
||||
if (it.isSimple())
|
||||
result << it.value();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Utils::Environment CocoQMakeSettings::buildEnvironment() const
|
||||
{
|
||||
if (!enabled())
|
||||
return Utils::Environment();
|
||||
|
||||
Utils::Environment env = m_buildConfig->environment();
|
||||
env.modify(m_buildConfig->userEnvironmentChanges());
|
||||
return env;
|
||||
}
|
||||
|
||||
void CocoQMakeSettings::setQMakeFeatures() const
|
||||
{
|
||||
if (!enabled())
|
||||
return;
|
||||
|
||||
Utils::Environment env = buildEnvironment();
|
||||
|
||||
const QString projectDir = m_buildConfig->project()->projectDirectory().nativePath();
|
||||
if (env.value(featuresVar) != projectDir) {
|
||||
// Bug in prependOrSet(): It does not recognize if QMAKEFEATURES contains a single path
|
||||
// without a colon and then appends it twice.
|
||||
env.prependOrSet(featuresVar, projectDir);
|
||||
}
|
||||
|
||||
Utils::EnvironmentItems diff = m_buildConfig->baseEnvironment().diff(env);
|
||||
m_buildConfig->setUserEnvironmentChanges(diff);
|
||||
}
|
||||
|
||||
bool CocoQMakeSettings::environmentSet() const
|
||||
{
|
||||
if (!enabled())
|
||||
return true;
|
||||
|
||||
const Utils::Environment env = buildEnvironment();
|
||||
const Utils::FilePath projectDir = m_buildConfig->project()->projectDirectory();
|
||||
const QString nativeProjectDir = projectDir.nativePath();
|
||||
return env.value(featuresVar) == nativeProjectDir
|
||||
|| env.value(featuresVar).startsWith(nativeProjectDir + projectDir.pathListSeparator());
|
||||
}
|
||||
|
||||
bool CocoQMakeSettings::validSettings() const
|
||||
{
|
||||
const bool configured = userArgumentList().contains(configAssignment());
|
||||
return enabled() && configured && environmentSet() && m_featureFile.exists()
|
||||
&& cocoPathValid();
|
||||
}
|
||||
|
||||
void CocoQMakeSettings::setCoverage(bool on)
|
||||
{
|
||||
QString args = m_qmakeStep->userArguments.unexpandedArguments();
|
||||
Utils::ProcessArgs::ArgIterator it{&args};
|
||||
|
||||
while (it.next()) {
|
||||
if (it.isSimple()) {
|
||||
const QString value = it.value();
|
||||
if (value.startsWith(pathAssignmentPrefix) || value == configAssignment())
|
||||
it.deleteArg();
|
||||
}
|
||||
}
|
||||
if (on) {
|
||||
it.appendArg(configAssignment());
|
||||
it.appendArg(pathAssignment());
|
||||
|
||||
setQMakeFeatures();
|
||||
m_featureFile.write();
|
||||
}
|
||||
|
||||
m_qmakeStep->userArguments.setArguments(args);
|
||||
}
|
||||
|
||||
QString CocoQMakeSettings::saveButtonText() const
|
||||
{
|
||||
return Tr::tr("Save");
|
||||
}
|
||||
|
||||
QString CocoQMakeSettings::configChanges() const
|
||||
{
|
||||
return "<table><tbody>"
|
||||
+ tableRow(
|
||||
"Additional qmake arguments: ",
|
||||
maybeQuote(configAssignment()) + " " + maybeQuote(pathAssignment()))
|
||||
+ tableRow(
|
||||
"Build environment: ", maybeQuote(QString(featuresVar) + "=" + projectDirectory()))
|
||||
+ tableRow("Feature File: ", maybeQuote(featureFilePath())) + "</tbody></table>";
|
||||
}
|
||||
|
||||
QString CocoQMakeSettings::projectDirectory() const
|
||||
{
|
||||
if (enabled())
|
||||
return m_buildConfig->project()->projectDirectory().nativePath();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
void CocoQMakeSettings::write(const QString &options, const QString &tweaks)
|
||||
{
|
||||
m_featureFile.setOptions(options);
|
||||
m_featureFile.setTweaks(tweaks);
|
||||
m_featureFile.write();
|
||||
}
|
||||
|
||||
QString CocoQMakeSettings::pathAssignment() const
|
||||
{
|
||||
return pathAssignmentPrefix + m_coco.directory().toUserOutput();
|
||||
}
|
||||
|
||||
bool CocoQMakeSettings::cocoPathValid() const
|
||||
{
|
||||
Utils::ProcessArgs::ConstArgIterator it{m_qmakeStep->userArguments.unexpandedArguments()};
|
||||
|
||||
while (it.next()) {
|
||||
if (it.isSimple()) {
|
||||
const QString value = it.value();
|
||||
if (value.startsWith(pathAssignmentPrefix) && value != pathAssignment())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
56
src/plugins/coco/cocobuild/cocoqmakesettings.h
Normal file
56
src/plugins/coco/cocobuild/cocoqmakesettings.h
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "buildsettings.h"
|
||||
#include "qmakefeaturefile.h"
|
||||
#include "settings/cocoinstallation.h"
|
||||
|
||||
#include <utils/commandline.h>
|
||||
#include <utils/environment.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
namespace QmakeProjectManager {
|
||||
class QMakeStep;
|
||||
class QmakeBuildConfiguration;
|
||||
}
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class CocoProjectWidget;
|
||||
|
||||
class CocoQMakeSettings : public BuildSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CocoQMakeSettings(ProjectExplorer::Project *project);
|
||||
~CocoQMakeSettings() override;
|
||||
|
||||
void read() override;
|
||||
bool validSettings() const override;
|
||||
void setCoverage(bool on) override;
|
||||
|
||||
QString saveButtonText() const override;
|
||||
QString configChanges() const override;
|
||||
QString projectDirectory() const override;
|
||||
void write(const QString &options, const QString &tweaks) override;
|
||||
|
||||
private:
|
||||
bool environmentSet() const;
|
||||
QString pathAssignment() const;
|
||||
const QStringList userArgumentList() const;
|
||||
Utils::Environment buildEnvironment() const;
|
||||
void setQMakeFeatures() const;
|
||||
bool cocoPathValid() const;
|
||||
|
||||
QmakeProjectManager::QmakeBuildConfiguration *m_buildConfig;
|
||||
QmakeProjectManager::QMakeStep *m_qmakeStep;
|
||||
|
||||
QMakeFeatureFile m_featureFile;
|
||||
CocoInstallation m_coco;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
73
src/plugins/coco/cocobuild/modificationfile.cpp
Normal file
73
src/plugins/coco/cocobuild/modificationfile.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "modificationfile.h"
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
static void cutTail(QStringList &list)
|
||||
{
|
||||
while (!list.isEmpty() && list.last().trimmed().isEmpty())
|
||||
list.removeLast();
|
||||
}
|
||||
|
||||
ModificationFile::ModificationFile() {}
|
||||
|
||||
bool ModificationFile::exists() const
|
||||
{
|
||||
return m_filePath.exists();
|
||||
}
|
||||
|
||||
void ModificationFile::clear()
|
||||
{
|
||||
m_options.clear();
|
||||
m_tweaks.clear();
|
||||
}
|
||||
|
||||
QStringList ModificationFile::contentOf(const Utils::FilePath &filePath) const
|
||||
{
|
||||
QFile resource(filePath.nativePath());
|
||||
resource.open(QIODevice::ReadOnly | QIODevice::Text);
|
||||
QTextStream inStream(&resource);
|
||||
|
||||
QStringList result;
|
||||
QString line;
|
||||
while (inStream.readLineInto(&line))
|
||||
result << line + '\n';
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList ModificationFile::currentModificationFile() const
|
||||
{
|
||||
QStringList lines;
|
||||
if (m_filePath.exists())
|
||||
lines = contentOf(m_filePath);
|
||||
else
|
||||
lines = defaultModificationFile();
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
void ModificationFile::setOptions(const QString &options)
|
||||
{
|
||||
m_options = options.split('\n', Qt::SkipEmptyParts);
|
||||
}
|
||||
|
||||
void ModificationFile::setOptions(const QStringList &options)
|
||||
{
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
void ModificationFile::setTweaks(const QString &tweaks)
|
||||
{
|
||||
m_tweaks = tweaks.split('\n', Qt::KeepEmptyParts);
|
||||
cutTail(m_tweaks);
|
||||
}
|
||||
|
||||
void ModificationFile::setTweaks(const QStringList &tweaks)
|
||||
{
|
||||
m_tweaks = tweaks;
|
||||
cutTail(m_tweaks);
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
51
src/plugins/coco/cocobuild/modificationfile.h
Normal file
51
src/plugins/coco/cocobuild/modificationfile.h
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/filepath.h>
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class ModificationFile
|
||||
{
|
||||
public:
|
||||
ModificationFile();
|
||||
|
||||
virtual void read() = 0;
|
||||
virtual void write() const = 0;
|
||||
|
||||
virtual void setProjectDirectory(const Utils::FilePath &projectDirectory) = 0;
|
||||
|
||||
virtual QString fileName() const = 0;
|
||||
QString nativePath() const { return m_filePath.nativePath(); }
|
||||
bool exists() const;
|
||||
|
||||
const QStringList &options() const { return m_options; }
|
||||
void setOptions(const QString &options);
|
||||
|
||||
const QStringList &tweaks() const { return m_tweaks; }
|
||||
void setTweaks(const QString &tweaks);
|
||||
|
||||
protected:
|
||||
void clear();
|
||||
|
||||
virtual QStringList defaultModificationFile() const = 0;
|
||||
QStringList contentOf(const Utils::FilePath &filePath) const;
|
||||
QStringList currentModificationFile() const;
|
||||
|
||||
void setFilePath(const Utils::FilePath &path) { m_filePath = path; }
|
||||
|
||||
void setOptions(const QStringList &options);
|
||||
void setTweaks(const QStringList &tweaks);
|
||||
|
||||
private:
|
||||
QStringList m_options;
|
||||
QStringList m_tweaks;
|
||||
|
||||
Utils::FilePath m_filePath;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
105
src/plugins/coco/cocobuild/qmakefeaturefile.cpp
Normal file
105
src/plugins/coco/cocobuild/qmakefeaturefile.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "qmakefeaturefile.h"
|
||||
|
||||
#include "cocopluginconstants.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QRegularExpression>
|
||||
#include <QTextStream>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
static const char assignment[] = "COVERAGE_OPTIONS = \\\n";
|
||||
static const char tweaksLine[] = "# User-supplied settings follow here:\n";
|
||||
|
||||
static void cutTail(QStringList &list)
|
||||
{
|
||||
while (!list.isEmpty() && list.last().trimmed().isEmpty())
|
||||
list.removeLast();
|
||||
}
|
||||
|
||||
QMakeFeatureFile::QMakeFeatureFile() {}
|
||||
|
||||
QString QMakeFeatureFile::fileName() const
|
||||
{
|
||||
return QString(Constants::PROFILE_NAME) + ".prf";
|
||||
}
|
||||
|
||||
void QMakeFeatureFile::setProjectDirectory(const Utils::FilePath &projectDirectory)
|
||||
{
|
||||
setFilePath(projectDirectory.pathAppended(fileName()));
|
||||
}
|
||||
|
||||
QString QMakeFeatureFile::fromFileLine(const QString &line) const
|
||||
{
|
||||
return line.chopped(2).trimmed().replace("\\\"", "\"");
|
||||
}
|
||||
|
||||
QString QMakeFeatureFile::toFileLine(const QString &option) const
|
||||
{
|
||||
QString line = option.trimmed().replace("\"", "\\\"");
|
||||
return " " + line + " \\\n";
|
||||
}
|
||||
|
||||
void QMakeFeatureFile::read()
|
||||
{
|
||||
clear();
|
||||
QStringList file = currentModificationFile();
|
||||
|
||||
{
|
||||
QStringList options;
|
||||
int i = file.indexOf(assignment);
|
||||
if (i != -1) {
|
||||
i++;
|
||||
while (i < file.size() && file[i].endsWith("\\\n")) {
|
||||
options += fromFileLine(file[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
setOptions(options);
|
||||
}
|
||||
{
|
||||
QStringList tweaks;
|
||||
int i = file.indexOf(tweaksLine);
|
||||
if (i != -1) {
|
||||
i++;
|
||||
while (i < file.size()) {
|
||||
tweaks += file[i].chopped(1);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
setTweaks(tweaks);
|
||||
}
|
||||
}
|
||||
|
||||
void QMakeFeatureFile::write() const
|
||||
{
|
||||
QFile out(nativePath());
|
||||
out.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||
|
||||
QTextStream outStream(&out);
|
||||
for (QString &line : defaultModificationFile()) {
|
||||
outStream << line;
|
||||
|
||||
if (line.startsWith(assignment)) {
|
||||
for (const QString &option : options()) {
|
||||
QString line = toFileLine(option);
|
||||
if (!line.isEmpty())
|
||||
outStream << line;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const QString &line : tweaks())
|
||||
outStream << line << "\n";
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
QStringList QMakeFeatureFile::defaultModificationFile() const
|
||||
{
|
||||
return contentOf(":/cocoplugin/files/cocoplugin.prf");
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
34
src/plugins/coco/cocobuild/qmakefeaturefile.h
Normal file
34
src/plugins/coco/cocobuild/qmakefeaturefile.h
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "modificationfile.h"
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class QMakeFeatureFile : public ModificationFile
|
||||
{
|
||||
public:
|
||||
QMakeFeatureFile();
|
||||
|
||||
void setProjectDirectory(const Utils::FilePath &projectDirectory) override;
|
||||
void read() override;
|
||||
void write() const override;
|
||||
|
||||
QString fileName() const override;
|
||||
|
||||
protected:
|
||||
QStringList defaultModificationFile() const override;
|
||||
|
||||
private:
|
||||
QString fromFileLine(const QString &line) const;
|
||||
QString toFileLine(const QString &option) const;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
@@ -1,17 +1,25 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cocobuild/cocobuildstep.h"
|
||||
#include "cocolanguageclient.h"
|
||||
#include "cocopluginconstants.h"
|
||||
#include "cocotr.h"
|
||||
#include "settings/cocoprojectsettingswidget.h"
|
||||
#include "settings/globalsettings.h"
|
||||
#include "settings/globalsettingspage.h"
|
||||
|
||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
#include <projectexplorer/projectpanelfactory.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <debugger/analyzer/analyzerconstants.h>
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
|
||||
#include <utils/environment.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/pathchooser.h>
|
||||
@@ -19,12 +27,17 @@
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFormLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
using namespace Core;
|
||||
using namespace Utils;
|
||||
|
||||
namespace Coco {
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Internal;
|
||||
|
||||
class CocoPlugin final : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -36,7 +49,7 @@ public:
|
||||
// FIXME: Kill m_client?
|
||||
}
|
||||
|
||||
void initialize() final
|
||||
void initLanguageServer()
|
||||
{
|
||||
ActionBuilder(this, "Coco.startCoco")
|
||||
.setText("Squish Coco ...")
|
||||
@@ -50,53 +63,112 @@ public:
|
||||
m_client->shutdown();
|
||||
m_client = nullptr;
|
||||
|
||||
QDialog dialog(ICore::dialogParent());
|
||||
dialog.setModal(true);
|
||||
auto layout = new QFormLayout();
|
||||
CocoInstallation coco;
|
||||
if (coco.isValid()) {
|
||||
QDialog dialog(ICore::dialogParent());
|
||||
dialog.setModal(true);
|
||||
auto layout = new QFormLayout();
|
||||
|
||||
const Environment env = Environment::systemEnvironment();
|
||||
const FilePath squishCocoPath = FilePath::fromUserInput(env.value("SQUISHCOCO"));
|
||||
const FilePath candidate = FilePath("coveragebrowser").searchInPath({squishCocoPath},
|
||||
FilePath::PrependToPath);
|
||||
PathChooser csmesChoser;
|
||||
csmesChoser.setHistoryCompleter("Coco.CSMes.history", true);
|
||||
csmesChoser.setExpectedKind(PathChooser::File);
|
||||
csmesChoser.setInitialBrowsePathBackup(PathChooser::homePath());
|
||||
csmesChoser.setPromptDialogFilter(Tr::tr("Coco instrumentation files (*.csmes)"));
|
||||
csmesChoser.setPromptDialogTitle(Tr::tr("Select a Squish Coco Instrumentation File"));
|
||||
layout->addRow(Tr::tr("CSMes file:"), &csmesChoser);
|
||||
QDialogButtonBox buttons(QDialogButtonBox::Cancel | QDialogButtonBox::Open);
|
||||
layout->addWidget(&buttons);
|
||||
dialog.setLayout(layout);
|
||||
dialog.resize(480, dialog.height());
|
||||
|
||||
PathChooser cocoChooser;
|
||||
if (!candidate.isEmpty())
|
||||
cocoChooser.setFilePath(candidate);
|
||||
cocoChooser.setExpectedKind(PathChooser::Command);
|
||||
cocoChooser.setPromptDialogTitle(Tr::tr("Select a Squish Coco CoverageBrowser Executable"));
|
||||
QObject::connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||
QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
|
||||
cocoChooser.setHistoryCompleter("Coco.CoverageBrowser.history", true);
|
||||
layout->addRow(Tr::tr("CoverageBrowser:"), &cocoChooser);
|
||||
PathChooser csmesChoser;
|
||||
csmesChoser.setHistoryCompleter("Coco.CSMes.history", true);
|
||||
csmesChoser.setExpectedKind(PathChooser::File);
|
||||
csmesChoser.setInitialBrowsePathBackup(FileUtils::homePath());
|
||||
csmesChoser.setPromptDialogFilter(Tr::tr("Coco instrumentation files (*.csmes)"));
|
||||
csmesChoser.setPromptDialogTitle(Tr::tr("Select a Squish Coco Instrumentation File"));
|
||||
layout->addRow(Tr::tr("CSMes:"), &csmesChoser);
|
||||
QDialogButtonBox buttons(QDialogButtonBox::Cancel | QDialogButtonBox::Open);
|
||||
layout->addItem(new QSpacerItem(0, 20, QSizePolicy::Expanding, QSizePolicy::MinimumExpanding));
|
||||
layout->addWidget(&buttons);
|
||||
dialog.setLayout(layout);
|
||||
dialog.resize(480, dialog.height());
|
||||
|
||||
QObject::connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||
QObject::connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
const FilePath cocoPath = cocoChooser.filePath();
|
||||
const FilePath csmesPath = csmesChoser.filePath();
|
||||
if (cocoPath.isExecutableFile() && csmesPath.exists()) {
|
||||
m_client = new CocoLanguageClient(cocoPath, csmesPath);
|
||||
m_client->start();
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
const FilePath cocoPath = coco.coverageBrowserPath();
|
||||
const FilePath csmesPath = csmesChoser.filePath();
|
||||
if (cocoPath.isExecutableFile() && csmesPath.exists()) {
|
||||
m_client = new CocoLanguageClient(cocoPath, csmesPath);
|
||||
m_client->start();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
QMessageBox msg;
|
||||
msg.setText(Tr::tr("No valid CoverageScanner found."));
|
||||
QPushButton *configButton = msg.addButton(Tr::tr("Configure"), QMessageBox::AcceptRole);
|
||||
msg.setStandardButtons(QMessageBox::Cancel);
|
||||
msg.exec();
|
||||
|
||||
if (msg.clickedButton() == configButton)
|
||||
Core::ICore::showOptionsDialog(Constants::COCO_SETTINGS_PAGE_ID);
|
||||
}
|
||||
}
|
||||
|
||||
bool initialize(const QStringList &arguments, QString *errorString);
|
||||
void addEntryToProjectSettings();
|
||||
|
||||
private:
|
||||
static void addBuildStep(ProjectExplorer::Target *target);
|
||||
|
||||
QMakeStepFactory m_qmakeStepFactory;
|
||||
CMakeStepFactory m_cmakeStepFactory;
|
||||
|
||||
CocoLanguageClient *m_client = nullptr;
|
||||
};
|
||||
|
||||
void CocoPlugin::addBuildStep(Target *target)
|
||||
{
|
||||
for (BuildConfiguration *config : target->buildConfigurations()) {
|
||||
if (BuildSettings::supportsBuildConfig(*config)) {
|
||||
BuildStepList *steps = config->buildSteps();
|
||||
|
||||
if (!steps->contains(Constants::COCO_STEP_ID))
|
||||
steps->insertStep(0, CocoBuildStep::create(config));
|
||||
|
||||
steps->firstOfType<CocoBuildStep>()->display(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CocoPlugin::initialize(const QStringList &arguments, QString *errorString)
|
||||
{
|
||||
Q_UNUSED(arguments)
|
||||
Q_UNUSED(errorString)
|
||||
|
||||
GlobalSettings::read();
|
||||
GlobalSettingsPage::instance().widget();
|
||||
addEntryToProjectSettings();
|
||||
|
||||
connect(ProjectManager::instance(), &ProjectManager::projectAdded, this, [&](Project *project) {
|
||||
if (Target *target = project->activeTarget())
|
||||
addBuildStep(target);
|
||||
|
||||
connect(project, &Project::addedTarget, this, [](Target *target) {
|
||||
addBuildStep(target);
|
||||
});
|
||||
});
|
||||
|
||||
initLanguageServer();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CocoPlugin::addEntryToProjectSettings()
|
||||
{
|
||||
auto panelFactory = new ProjectPanelFactory;
|
||||
panelFactory->setPriority(50);
|
||||
panelFactory->setDisplayName(tr("Coco Code Coverage"));
|
||||
panelFactory->setSupportsFunction([](Project *project) {
|
||||
if (Target *target = project->activeTarget()) {
|
||||
if (BuildConfiguration *abc = target->activeBuildConfiguration())
|
||||
return BuildSettings::supportsBuildConfig(*abc);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
panelFactory->setCreateWidgetFunction(
|
||||
[](Project *project) { return new CocoProjectSettingsWidget(project); });
|
||||
}
|
||||
|
||||
} // namespace Coco
|
||||
|
||||
#include "cocoplugin.moc"
|
||||
|
10
src/plugins/coco/cocoplugin.qrc
Normal file
10
src/plugins/coco/cocoplugin.qrc
Normal file
@@ -0,0 +1,10 @@
|
||||
<RCC>
|
||||
<qresource prefix="/cocoplugin">
|
||||
<file>images/SquishCoco_48x48.png</file>
|
||||
<file>files/cocoplugin.prf</file>
|
||||
<file>files/cocoplugin.cmake</file>
|
||||
<file>files/cocoplugin-clang.cmake</file>
|
||||
<file>files/cocoplugin-gcc.cmake</file>
|
||||
<file>files/cocoplugin-visualstudio.cmake</file>
|
||||
</qresource>
|
||||
</RCC>
|
12
src/plugins/coco/cocoplugin_global.h
Normal file
12
src/plugins/coco/cocoplugin_global.h
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(COCO_LIBRARY)
|
||||
# define COCOPLUGINSHARED_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define COCOPLUGINSHARED_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
23
src/plugins/coco/cocopluginconstants.h
Normal file
23
src/plugins/coco/cocopluginconstants.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Coco {
|
||||
namespace Constants {
|
||||
|
||||
const char ACTION_ID[] = "coco.Action";
|
||||
const char MENU_ID[] = "coco.Menu";
|
||||
const char COCO_STEP_ID[] = "Cocoplugin.BuildStep";
|
||||
|
||||
const char PROFILE_NAME[] = "cocoplugin"; // Name of the Coco profile file
|
||||
|
||||
const char COCO_SETTINGS_GROUP[] = "Coco";
|
||||
const char COCO_SETTINGS_PAGE_ID[] = "A.CocoOptions";
|
||||
|
||||
// Project settings
|
||||
const char SETTINGS_NAME_KEY[] = "CocoProjectSettings";
|
||||
const char SELECTION_DIR_KEY[] = "SelectionDir";
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace Coco
|
30
src/plugins/coco/common.cpp
Normal file
30
src/plugins/coco/common.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "cocopluginconstants.h"
|
||||
|
||||
#include <coreplugin/messagemanager.h>
|
||||
|
||||
QString maybeQuote(const QString &str)
|
||||
{
|
||||
if ((str.contains(' ') || str.contains('\t')) && !str.startsWith('"'))
|
||||
return '"' + str + '"';
|
||||
else
|
||||
return str;
|
||||
}
|
||||
|
||||
void logSilently(const QString &msg)
|
||||
{
|
||||
static const QString prefix = QString{"[%1] "}.arg(Coco::Constants::PROFILE_NAME);
|
||||
|
||||
Core::MessageManager::writeSilently(prefix + msg);
|
||||
}
|
||||
|
||||
void logFlashing(const QString &msg)
|
||||
{
|
||||
static const QString prefix = QString{"[%1] "}.arg(Coco::Constants::PROFILE_NAME);
|
||||
|
||||
Core::MessageManager::writeFlashing(prefix + msg);
|
||||
}
|
14
src/plugins/coco/common.h
Normal file
14
src/plugins/coco/common.h
Normal file
@@ -0,0 +1,14 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
QString maybeQuote(const QString &str);
|
||||
|
||||
void logSilently(const QString &msg);
|
||||
void logFlashing(const QString &msg);
|
||||
|
||||
#endif // COMMON_H
|
8
src/plugins/coco/files/cocoplugin-clang.cmake
Normal file
8
src/plugins/coco/files/cocoplugin-clang.cmake
Normal file
@@ -0,0 +1,8 @@
|
||||
# Created by the Coco Qt Creator plugin. Do not edit!
|
||||
|
||||
set(CMAKE_C_COMPILER clang)
|
||||
set(CMAKE_CXX_COMPILER clang++)
|
||||
set(CMAKE_AR ar)
|
||||
set(CMAKE_LINKER clang)
|
||||
|
||||
include(cocoplugin.cmake)
|
8
src/plugins/coco/files/cocoplugin-gcc.cmake
Normal file
8
src/plugins/coco/files/cocoplugin-gcc.cmake
Normal file
@@ -0,0 +1,8 @@
|
||||
# Created by the Coco Qt Creator plugin. Do not edit!
|
||||
|
||||
set(CMAKE_C_COMPILER gcc)
|
||||
set(CMAKE_CXX_COMPILER g++)
|
||||
set(CMAKE_AR ar)
|
||||
set(CMAKE_LINKER gcc)
|
||||
|
||||
include(cocoplugin.cmake)
|
8
src/plugins/coco/files/cocoplugin-visualstudio.cmake
Normal file
8
src/plugins/coco/files/cocoplugin-visualstudio.cmake
Normal file
@@ -0,0 +1,8 @@
|
||||
# Created by the Coco Qt Creator plugin. Do not edit!
|
||||
|
||||
set(CMAKE_C_COMPILER cl)
|
||||
set(CMAKE_CXX_COMPILER cl)
|
||||
set(CMAKE_AR lib)
|
||||
set(CMAKE_LINKER link)
|
||||
|
||||
include(cocoplugin.cmake)
|
87
src/plugins/coco/files/cocoplugin.cmake
Normal file
87
src/plugins/coco/files/cocoplugin.cmake
Normal file
@@ -0,0 +1,87 @@
|
||||
# Created by the Coco Qt Creator plugin. Do not edit!
|
||||
|
||||
set(coverage_flags_list
|
||||
)
|
||||
list(JOIN coverage_flags_list " " coverage_flags)
|
||||
|
||||
foreach(var IN ITEMS CMAKE_C_COMPILER CMAKE_CXX_COMPILER)
|
||||
if(NOT DEFINED ${var})
|
||||
message(FATAL_ERROR "Variable ${var} must be defined.")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(CMAKE_C_FLAGS_INIT "${coverage_flags}"
|
||||
CACHE STRING "Coverage flags for the C compiler." FORCE)
|
||||
set(CMAKE_CXX_FLAGS_INIT "${coverage_flags}"
|
||||
CACHE STRING "Coverage flags for the C++ compiler." FORCE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_INIT "${coverage_flags}"
|
||||
CACHE STRING "Coverage flags for the linker." FORCE)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_INIT "${coverage_flags}"
|
||||
CACHE STRING "Coverage flags to link shared libraries." FORCE)
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_INIT "${coverage_flags}"
|
||||
CACHE STRING "Coverage flags to link static libraries." FORCE)
|
||||
|
||||
if (DEFINED ENV{SQUISHCOCO})
|
||||
set(cocopath $ENV{SQUISHCOCO})
|
||||
else()
|
||||
find_file(cocopath SquishCoco
|
||||
PATHS "$ENV{HOME}" /opt/ "/Applications"
|
||||
REQUIRED
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set(wrapperdir "${cocopath}/")
|
||||
elseif(CMAKE_HOST_UNIX)
|
||||
set(wrapperdir "${cocopath}/bin/")
|
||||
elseif(MINGW)
|
||||
set(wrapperdir "${cocopath}\\bin\\")
|
||||
else()
|
||||
set(wrapperdir "${cocopath}\\" )
|
||||
endif()
|
||||
|
||||
get_filename_component(c_compiler ${CMAKE_C_COMPILER} NAME)
|
||||
find_program(code_coverage_c_compiler cs${c_compiler}
|
||||
PATHS ${wrapperdir}
|
||||
REQUIRED NO_DEFAULT_PATH)
|
||||
set(CMAKE_C_COMPILER "${code_coverage_c_compiler}"
|
||||
CACHE FILEPATH "CoverageScanner wrapper for C compiler" FORCE)
|
||||
|
||||
get_filename_component(cxx_compiler ${CMAKE_CXX_COMPILER} NAME)
|
||||
find_program(code_coverage_cxx_compiler cs${cxx_compiler}
|
||||
PATHS ${wrapperdir}
|
||||
REQUIRED NO_DEFAULT_PATH)
|
||||
set(CMAKE_CXX_COMPILER "${code_coverage_cxx_compiler}"
|
||||
CACHE FILEPATH "CoverageScanner wrapper for C++ compiler" FORCE)
|
||||
|
||||
if(DEFINED CMAKE_LINKER)
|
||||
get_filename_component(linker_prog ${CMAKE_LINKER} NAME)
|
||||
find_program(code_coverage_linker cs${linker_prog}
|
||||
PATHS ${wrapperdir}
|
||||
REQUIRED NO_DEFAULT_PATH)
|
||||
set(CMAKE_LINKER "${code_coverage_linker}"
|
||||
CACHE FILEPATH "CoverageScanner wrapper for linker" FORCE)
|
||||
elseif(${c_compiler} STREQUAL "cl.exe") # special case for Visual Studio
|
||||
find_program(code_coverage_linker "cslink.exe"
|
||||
PATHS ${wrapperdir}
|
||||
REQUIRED NO_DEFAULT_PATH)
|
||||
set(CMAKE_LINKER "${code_coverage_linker}"
|
||||
CACHE FILEPATH "CoverageScanner wrapper for linker" FORCE)
|
||||
endif()
|
||||
|
||||
if(DEFINED CMAKE_AR)
|
||||
get_filename_component(ar_prog ${CMAKE_AR} NAME)
|
||||
find_program(code_coverage_ar cs${ar_prog}
|
||||
PATHS ${wrapperdir}
|
||||
REQUIRED NO_DEFAULT_PATH)
|
||||
set(CMAKE_AR "${code_coverage_ar}"
|
||||
CACHE FILEPATH "CoverageScanner wrapper for ar" FORCE)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(
|
||||
cocopath
|
||||
code_coverage_c_compiler code_coverage_cxx_compiler code_coverage_linker code_coverage_ar
|
||||
)
|
||||
|
||||
# User-supplied settings follow here:
|
33
src/plugins/coco/files/cocoplugin.prf
Normal file
33
src/plugins/coco/files/cocoplugin.prf
Normal file
@@ -0,0 +1,33 @@
|
||||
# Created by the Coco plugin. Do not edit!
|
||||
|
||||
COVERAGE_OPTIONS = \
|
||||
|
||||
defineReplace(toCoco) {
|
||||
cmd = $$1
|
||||
path = $$take_first(cmd)
|
||||
prog = $$basename(path)
|
||||
|
||||
return(cs$$prog $$cmd)
|
||||
}
|
||||
|
||||
isEmpty(COCOPATH): error(The variable COCOPATH must be set)
|
||||
|
||||
macos: wrapperdir = $$COCOPATH
|
||||
else: unix: wrapperdir = $$COCOPATH/bin
|
||||
else: win32: {
|
||||
win32-arm-msvc*|win32-x86-msvc*: wrapperdir = $$COCOPATH/visualstudio
|
||||
else: win32-arm64-msvc*|win32-x64-msvc*: wrapperdir = $$COCOPATH/visualstudio_x64
|
||||
else: wrapperdir = $$COCOPATH
|
||||
}
|
||||
|
||||
QMAKE_CFLAGS += $$COVERAGE_OPTIONS
|
||||
QMAKE_CXXFLAGS += $$COVERAGE_OPTIONS
|
||||
QMAKE_LFLAGS += $$COVERAGE_OPTIONS
|
||||
|
||||
QMAKE_AR = $$wrapperdir/$$toCoco($$QMAKE_AR)
|
||||
QMAKE_CC = $$wrapperdir/$$toCoco($$QMAKE_CC)
|
||||
QMAKE_CXX = $$wrapperdir/$$toCoco($$QMAKE_CXX)
|
||||
QMAKE_LINK = $$wrapperdir/$$toCoco($$QMAKE_LINK)
|
||||
QMAKE_LINK_SHLIB_CMD = $$wrapperdir/$$toCoco($$QMAKE_LINK_SHLIB_CMD)
|
||||
|
||||
# User-supplied settings follow here:
|
BIN
src/plugins/coco/images/SquishCoco_48x48.png
Normal file
BIN
src/plugins/coco/images/SquishCoco_48x48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 594 B |
177
src/plugins/coco/settings/cocoinstallation.cpp
Normal file
177
src/plugins/coco/settings/cocoinstallation.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cocoinstallation.h"
|
||||
|
||||
#include "cocotr.h"
|
||||
#include "common.h"
|
||||
#include "globalsettings.h"
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
|
||||
#include <QProcess>
|
||||
#include <QStandardPaths>
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
struct CocoInstallationPrivate
|
||||
{
|
||||
Utils::FilePath cocoPath;
|
||||
bool isValid = false;
|
||||
QString errorMessage = Tr::tr("Error: Coco installation directory not set. (This can't happen.)");
|
||||
};
|
||||
|
||||
CocoInstallationPrivate *CocoInstallation::d = nullptr;
|
||||
|
||||
CocoInstallation::CocoInstallation()
|
||||
{
|
||||
if (!d)
|
||||
d = new CocoInstallationPrivate;
|
||||
}
|
||||
|
||||
Utils::FilePath CocoInstallation::directory() const
|
||||
{
|
||||
return d->cocoPath;
|
||||
}
|
||||
|
||||
Utils::FilePath CocoInstallation::coverageBrowserPath() const
|
||||
{
|
||||
QString browserPath;
|
||||
|
||||
if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost())
|
||||
browserPath = "bin/coveragebrowser";
|
||||
else
|
||||
browserPath = "coveragebrowser.exe";
|
||||
|
||||
return d->cocoPath.resolvePath(browserPath);
|
||||
}
|
||||
|
||||
void CocoInstallation::setDirectory(const Utils::FilePath &dir)
|
||||
{
|
||||
if (isCocoDirectory(dir)) {
|
||||
d->cocoPath = dir;
|
||||
d->isValid = true;
|
||||
d->errorMessage = "";
|
||||
verifyCocoDirectory();
|
||||
}
|
||||
else {
|
||||
d->cocoPath = Utils::FilePath();
|
||||
d->isValid = false;
|
||||
d->errorMessage
|
||||
= Tr::tr("Error: Coco installation directory not found at \"%1\".").arg(dir.nativePath());
|
||||
}
|
||||
}
|
||||
|
||||
Utils::FilePath CocoInstallation::coverageScannerPath(const Utils::FilePath &cocoDir) const
|
||||
{
|
||||
QString scannerPath;
|
||||
|
||||
if (Utils::HostOsInfo::isAnyUnixHost() || Utils::HostOsInfo::isMacHost())
|
||||
scannerPath = "bin/coveragescanner";
|
||||
else
|
||||
scannerPath = "coveragescanner.exe";
|
||||
|
||||
return cocoDir.resolvePath(scannerPath);
|
||||
}
|
||||
|
||||
bool CocoInstallation::isCocoDirectory(const Utils::FilePath &cocoDir) const
|
||||
{
|
||||
return coverageScannerPath(cocoDir).exists();
|
||||
}
|
||||
|
||||
void CocoInstallation::logError(const QString &msg)
|
||||
{
|
||||
logFlashing(msg);
|
||||
d->isValid = false;
|
||||
d->errorMessage = msg;
|
||||
}
|
||||
|
||||
bool CocoInstallation::verifyCocoDirectory()
|
||||
{
|
||||
QString coveragescanner = coverageScannerPath(d->cocoPath).nativePath();
|
||||
|
||||
QProcess proc;
|
||||
proc.setProgram(coveragescanner);
|
||||
proc.setArguments({"--cs-help"});
|
||||
proc.start();
|
||||
|
||||
if (!proc.waitForStarted()) {
|
||||
logError(Tr::tr("Error: Coveragescanner at \"%1\" did not start.").arg(coveragescanner));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!proc.waitForFinished()) {
|
||||
logError(Tr::tr("Error: Coveragescanner at \"%1\" did not finish.").arg(coveragescanner));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString result = QString::fromLatin1(proc.readAll());
|
||||
static const QRegularExpression linebreak("\n|\r\n|\r");
|
||||
QStringList lines = result.split(linebreak, Qt::SkipEmptyParts);
|
||||
|
||||
const qsizetype n = lines.size();
|
||||
if (n >= 2 && lines[n - 2].startsWith("Version:") && lines[n - 1].startsWith("Date:")) {
|
||||
logSilently(Tr::tr("Valid CoverageScanner found at \"%1\":").arg(coveragescanner));
|
||||
logSilently(" " + lines[n - 2]);
|
||||
logSilently(" " + lines[n - 1]);
|
||||
return true;
|
||||
} else {
|
||||
logError(
|
||||
Tr::tr("Error: Coveragescanner at \"%1\" did not run correctly.").arg(coveragescanner));
|
||||
for (const QString &l : lines) {
|
||||
logSilently(l);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CocoInstallation::isValid() const
|
||||
{
|
||||
return d->isValid;
|
||||
}
|
||||
|
||||
QString CocoInstallation::errorMessage() const
|
||||
{
|
||||
return d->errorMessage;
|
||||
}
|
||||
|
||||
void CocoInstallation::tryPath(const QString &path)
|
||||
{
|
||||
if (d->isValid)
|
||||
return;
|
||||
|
||||
const auto fpath = Utils::FilePath::fromString(path);
|
||||
const QString nativePath = fpath.nativePath();
|
||||
if (isCocoDirectory(fpath)) {
|
||||
logSilently(Tr::tr("Found Coco directory \"%1\".").arg(nativePath));
|
||||
setDirectory(fpath);
|
||||
GlobalSettings::save();
|
||||
} else
|
||||
logSilently(Tr::tr("Checked Coco directory \"%1\".").arg(nativePath));
|
||||
}
|
||||
|
||||
QString CocoInstallation::envVar(const QString &var) const
|
||||
{
|
||||
return QProcessEnvironment::systemEnvironment().value(var);
|
||||
}
|
||||
|
||||
void CocoInstallation::findDefaultDirectory()
|
||||
{
|
||||
if (Utils::HostOsInfo::isMacHost())
|
||||
tryPath("/Applications/SquishCoco");
|
||||
else if (Utils::HostOsInfo::isAnyUnixHost()) {
|
||||
tryPath((Utils::FileUtils::homePath() / "SquishCoco").nativePath());
|
||||
tryPath("/opt/SquishCoco");
|
||||
} else {
|
||||
tryPath(envVar("SQUISHCOCO"));
|
||||
QStringList homeDirs = QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
|
||||
if (!homeDirs.isEmpty())
|
||||
tryPath(homeDirs[0] + "/squishcoco");
|
||||
tryPath(envVar("ProgramFiles") + "\\squishcoco");
|
||||
tryPath(envVar("ProgramFiles(x86)") + "\\squishcoco");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
39
src/plugins/coco/settings/cocoinstallation.h
Normal file
39
src/plugins/coco/settings/cocoinstallation.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/filepath.h>
|
||||
|
||||
class QString;
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
struct CocoInstallationPrivate;
|
||||
|
||||
// Borg pattern: There are many instances of this class, but all are the same.
|
||||
class CocoInstallation
|
||||
{
|
||||
public:
|
||||
CocoInstallation();
|
||||
|
||||
Utils::FilePath directory() const;
|
||||
Utils::FilePath coverageBrowserPath() const;
|
||||
void setDirectory(const Utils::FilePath &dir);
|
||||
void findDefaultDirectory();
|
||||
|
||||
bool isValid() const;
|
||||
QString errorMessage() const;
|
||||
|
||||
private:
|
||||
Utils::FilePath coverageScannerPath(const Utils::FilePath &cocoDir) const;
|
||||
void logError(const QString &msg);
|
||||
bool isCocoDirectory(const Utils::FilePath &cocoDir) const;
|
||||
bool verifyCocoDirectory();
|
||||
void tryPath(const QString &path);
|
||||
QString envVar(const QString &var) const;
|
||||
|
||||
static CocoInstallationPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
40
src/plugins/coco/settings/cocoprojectsettingswidget.cpp
Normal file
40
src/plugins/coco/settings/cocoprojectsettingswidget.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "cocoprojectsettingswidget.h"
|
||||
|
||||
#include "cocobuild/cocoprojectwidget.h"
|
||||
#include "cocopluginconstants.h"
|
||||
|
||||
#include <cmakeprojectmanager/cmakeprojectconstants.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
CocoProjectSettingsWidget::CocoProjectSettingsWidget(ProjectExplorer::Project *project)
|
||||
: m_layout{new QVBoxLayout}
|
||||
{
|
||||
setUseGlobalSettingsCheckBoxVisible(false);
|
||||
setGlobalSettingsId(Constants::COCO_SETTINGS_PAGE_ID);
|
||||
|
||||
if (auto *target = project->activeTarget()) {
|
||||
auto abc = target->activeBuildConfiguration();
|
||||
|
||||
if (abc->id() == QmakeProjectManager::Constants::QMAKE_BC_ID
|
||||
|| abc->id() == CMakeProjectManager::Constants::CMAKE_BUILDCONFIGURATION_ID)
|
||||
m_layout->addWidget(new CocoProjectWidget(project, *abc));
|
||||
}
|
||||
setLayout(m_layout);
|
||||
}
|
||||
|
||||
CocoProjectSettingsWidget::~CocoProjectSettingsWidget()
|
||||
{
|
||||
delete m_layout;
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
28
src/plugins/coco/settings/cocoprojectsettingswidget.h
Normal file
28
src/plugins/coco/settings/cocoprojectsettingswidget.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <projectexplorer/projectsettingswidget.h>
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Project;
|
||||
}
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class CocoProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CocoProjectSettingsWidget(ProjectExplorer::Project *project);
|
||||
~CocoProjectSettingsWidget();
|
||||
|
||||
private:
|
||||
QVBoxLayout *m_layout;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
53
src/plugins/coco/settings/globalsettings.cpp
Normal file
53
src/plugins/coco/settings/globalsettings.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "globalsettings.h"
|
||||
|
||||
#include "cocoinstallation.h"
|
||||
#include "cocopluginconstants.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/filepath.h>
|
||||
|
||||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
|
||||
namespace Coco::Internal {
|
||||
namespace GlobalSettings {
|
||||
|
||||
static const char DIRECTORY[] = "CocoDirectory";
|
||||
|
||||
void read()
|
||||
{
|
||||
CocoInstallation coco;
|
||||
bool directoryInSettings = false;
|
||||
|
||||
Utils::QtcSettings *s = Core::ICore::settings();
|
||||
s->beginGroup(Constants::COCO_SETTINGS_GROUP);
|
||||
const QStringList keys = s->allKeys();
|
||||
for (const QString &keyString : keys) {
|
||||
Utils::Key key(keyString.toLatin1());
|
||||
if (key == DIRECTORY) {
|
||||
coco.setDirectory(Utils::FilePath::fromUserInput(s->value(key).toString()));
|
||||
directoryInSettings = true;
|
||||
} else
|
||||
s->remove(key);
|
||||
}
|
||||
s->endGroup();
|
||||
|
||||
if (!directoryInSettings)
|
||||
coco.findDefaultDirectory();
|
||||
|
||||
GlobalSettings::save();
|
||||
}
|
||||
|
||||
void save()
|
||||
{
|
||||
Utils::QtcSettings *s = Core::ICore::settings();
|
||||
s->beginGroup(Constants::COCO_SETTINGS_GROUP);
|
||||
s->setValue(DIRECTORY, CocoInstallation().directory().toUserOutput());
|
||||
s->endGroup();
|
||||
}
|
||||
|
||||
} // namespace GlobalSettings
|
||||
} // namespace Coco::Internal
|
13
src/plugins/coco/settings/globalsettings.h
Normal file
13
src/plugins/coco/settings/globalsettings.h
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Coco::Internal {
|
||||
namespace GlobalSettings {
|
||||
|
||||
void read();
|
||||
void save();
|
||||
|
||||
} // namespace GlobalSettings
|
||||
} // namespace Coco::Internal
|
121
src/plugins/coco/settings/globalsettingspage.cpp
Normal file
121
src/plugins/coco/settings/globalsettingspage.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "globalsettingspage.h"
|
||||
|
||||
#include "cocoinstallation.h"
|
||||
#include "cocopluginconstants.h"
|
||||
#include "cocotr.h"
|
||||
#include "globalsettings.h"
|
||||
|
||||
#include <utils/fancylineedit.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
GlobalSettingsWidget::GlobalSettingsWidget(QFrame *parent)
|
||||
: QFrame(parent)
|
||||
{
|
||||
m_cocoPathAspect.setDefaultPathValue(m_coco.directory());
|
||||
m_cocoPathAspect.setExpectedKind(Utils::PathChooser::ExistingDirectory);
|
||||
m_cocoPathAspect.setPromptDialogTitle(Tr::tr("Coco Installation Directory"));
|
||||
|
||||
connect(
|
||||
&m_cocoPathAspect,
|
||||
&Utils::FilePathAspect::changed,
|
||||
this,
|
||||
&GlobalSettingsWidget::onCocoPathChanged);
|
||||
|
||||
using namespace Layouting;
|
||||
Form{
|
||||
Column{
|
||||
Row{Tr::tr("Coco Directory"), m_cocoPathAspect},
|
||||
Row{m_messageLabel}}
|
||||
}.attachTo(this);
|
||||
}
|
||||
|
||||
void GlobalSettingsWidget::onCocoPathChanged()
|
||||
{
|
||||
if (!verifyCocoDirectory(m_cocoPathAspect()))
|
||||
m_cocoPathAspect.setValue(m_previousCocoDir, Utils::BaseAspect::BeQuiet);
|
||||
}
|
||||
|
||||
bool GlobalSettingsWidget::verifyCocoDirectory(const Utils::FilePath &cocoDir)
|
||||
{
|
||||
m_coco.setDirectory(cocoDir);
|
||||
m_messageLabel.setText(m_coco.errorMessage());
|
||||
if (m_coco.isValid())
|
||||
m_messageLabel.setIconType(Utils::InfoLabel::None);
|
||||
else
|
||||
m_messageLabel.setIconType(Utils::InfoLabel::Error);
|
||||
return m_coco.isValid();
|
||||
}
|
||||
|
||||
void GlobalSettingsWidget::apply()
|
||||
{
|
||||
if (!verifyCocoDirectory(widgetCocoDir()))
|
||||
return;
|
||||
|
||||
m_coco.setDirectory(widgetCocoDir());
|
||||
GlobalSettings::save();
|
||||
|
||||
emit updateCocoDir();
|
||||
}
|
||||
|
||||
void GlobalSettingsWidget::cancel()
|
||||
{
|
||||
m_coco.setDirectory(m_previousCocoDir);
|
||||
}
|
||||
|
||||
void GlobalSettingsWidget::setVisible(bool visible)
|
||||
{
|
||||
QFrame::setVisible(visible);
|
||||
m_previousCocoDir = m_coco.directory();
|
||||
}
|
||||
|
||||
Utils::FilePath GlobalSettingsWidget::widgetCocoDir() const
|
||||
{
|
||||
return Utils::FilePath::fromUserInput(m_cocoPathAspect.value());
|
||||
}
|
||||
|
||||
GlobalSettingsPage::GlobalSettingsPage()
|
||||
: m_widget(nullptr)
|
||||
{
|
||||
setId(Constants::COCO_SETTINGS_PAGE_ID);
|
||||
setDisplayName(QCoreApplication::translate("Coco", "Coco"));
|
||||
setCategory("I.Coco"); // Category I contains also the C++ settings.
|
||||
setDisplayCategory(QCoreApplication::translate("Coco", "Coco"));
|
||||
setCategoryIconPath(":/cocoplugin/images/SquishCoco_48x48.png");
|
||||
}
|
||||
|
||||
GlobalSettingsPage &GlobalSettingsPage::instance()
|
||||
{
|
||||
static GlobalSettingsPage instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
GlobalSettingsWidget *GlobalSettingsPage::widget()
|
||||
{
|
||||
if (!m_widget)
|
||||
m_widget = new GlobalSettingsWidget;
|
||||
return m_widget;
|
||||
}
|
||||
|
||||
void GlobalSettingsPage::apply()
|
||||
{
|
||||
if (m_widget)
|
||||
m_widget->apply();
|
||||
}
|
||||
|
||||
void GlobalSettingsPage::cancel()
|
||||
{
|
||||
if (m_widget)
|
||||
m_widget->cancel();
|
||||
}
|
||||
|
||||
void GlobalSettingsPage::finish()
|
||||
{
|
||||
delete m_widget;
|
||||
}
|
||||
|
||||
} // namespace Coco::Internal
|
59
src/plugins/coco/settings/globalsettingspage.h
Normal file
59
src/plugins/coco/settings/globalsettingspage.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cocoinstallation.h"
|
||||
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
namespace Coco::Internal {
|
||||
|
||||
class GlobalSettingsWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GlobalSettingsWidget(QFrame *parent = nullptr);
|
||||
|
||||
void apply();
|
||||
void cancel();
|
||||
|
||||
signals:
|
||||
void updateCocoDir();
|
||||
|
||||
public slots:
|
||||
void setVisible(bool visible) override;
|
||||
|
||||
private:
|
||||
void onCocoPathChanged();
|
||||
|
||||
Utils::FilePath widgetCocoDir() const;
|
||||
bool verifyCocoDirectory(const Utils::FilePath &cocoDir);
|
||||
|
||||
Utils::FilePathAspect m_cocoPathAspect;
|
||||
Utils::TextDisplay m_messageLabel;
|
||||
|
||||
CocoInstallation m_coco;
|
||||
Utils::FilePath m_previousCocoDir;
|
||||
};
|
||||
|
||||
class GlobalSettingsPage : public Core::IOptionsPage
|
||||
{
|
||||
public:
|
||||
static GlobalSettingsPage &instance();
|
||||
|
||||
GlobalSettingsWidget *widget() override;
|
||||
void apply() override;
|
||||
void cancel() override;
|
||||
void finish() override;
|
||||
|
||||
private:
|
||||
GlobalSettingsPage();
|
||||
|
||||
QPointer<GlobalSettingsWidget> m_widget;
|
||||
};
|
||||
|
||||
} // namespace Coco::Internal
|
Reference in New Issue
Block a user