Merge remote-tracking branch 'origin/7.0'

Conflicts:
	src/plugins/webassembly/webassemblytoolchain.cpp

Change-Id: Ia75c783e3ecab1f97de2b5c73a0979c49da82009
This commit is contained in:
Eike Ziller
2022-03-18 15:57:59 +01:00
52 changed files with 355 additions and 199 deletions

View File

@@ -479,7 +479,8 @@ bool checkParameters(const QSsh::SshConnectionParameters &params)
void printSetupHelp()
{
qInfo() << "In order to run this test properly it requires some setup (example for fedora):\n"
qInfo() << "\n\n"
"In order to run this test properly it requires some setup (example for fedora):\n"
"1. Run a server on the host to connect to:\n"
" systemctl start sshd\n"
"2. Create your own ssh key (needed only once). For fedora it needs ecdsa type:\n"

View File

@@ -111,6 +111,7 @@ namespace Internal {
void popupRequested(bool focus);
void handleExpandCollapseToolButton(bool checked);
void updateFilterButton();
QList<QWidget *> toolBarWidgets();
SearchResultWindow *q;
QList<Internal::SearchResultWidget *> m_searchResultWidgets;
@@ -120,9 +121,9 @@ namespace Internal {
QAction *m_expandCollapseAction;
static const bool m_initiallyExpand;
QWidget *m_spacer;
QLabel *m_historyLabel;
QLabel *m_historyLabel = nullptr;
QWidget *m_spacer2;
QComboBox *m_recentSearchesBox;
QComboBox *m_recentSearchesBox = nullptr;
QStackedWidget *m_widget;
QList<SearchResult *> m_searchResults;
int m_currentIndex;
@@ -139,20 +140,13 @@ namespace Internal {
m_expandCollapseButton(nullptr),
m_expandCollapseAction(new QAction(tr("Expand All"), window)),
m_spacer(new QWidget),
m_historyLabel(new QLabel(tr("History:"))),
m_spacer2(new QWidget),
m_recentSearchesBox(new QComboBox),
m_widget(new QStackedWidget),
m_currentIndex(0),
m_tabWidth(8)
{
m_spacer->setMinimumWidth(30);
m_spacer2->setMinimumWidth(5);
m_recentSearchesBox->setProperty("drawleftborder", true);
m_recentSearchesBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_recentSearchesBox->addItem(tr("New Search"));
connect(m_recentSearchesBox, QOverload<int>::of(&QComboBox::activated),
this, &SearchResultWindowPrivate::setCurrentIndexWithFocus);
m_widget->setWindowTitle(q->displayName());
@@ -194,6 +188,7 @@ namespace Internal {
void SearchResultWindowPrivate::setCurrentIndex(int index, bool focus)
{
QTC_ASSERT(m_recentSearchesBox, return );
if (isSearchVisible())
m_searchResultWidgets.at(visibleSearchIndex())->notifyVisibilityChanged(false);
m_currentIndex = index;
@@ -217,6 +212,7 @@ namespace Internal {
void SearchResultWindowPrivate::moveWidgetToTop()
{
QTC_ASSERT(m_recentSearchesBox, return );
auto widget = qobject_cast<SearchResultWidget *>(sender());
QTC_ASSERT(widget, return);
const int index = m_searchResultWidgets.indexOf(widget);
@@ -458,8 +454,7 @@ QWidget *SearchResultWindow::outputWidget(QWidget *)
*/
QList<QWidget*> SearchResultWindow::toolBarWidgets() const
{
return {d->m_expandCollapseButton, d->m_filterButton, d->m_newSearchButton, d->m_spacer,
d->m_historyLabel, d->m_spacer2, d->m_recentSearchesBox};
return d->toolBarWidgets();
}
/*!
@@ -497,16 +492,19 @@ SearchResult *SearchResultWindow::startNewSearch(const QString &label,
PreserveCaseMode preserveCaseMode,
const QString &cfgGroup)
{
if (d->m_searchResults.size() >= MAX_SEARCH_HISTORY) {
if (d->m_currentIndex >= d->m_recentSearchesBox->count() - 1) {
// temporarily set the index to the last but one existing
d->m_currentIndex = d->m_recentSearchesBox->count() - 2;
if (QTC_GUARD(d->m_recentSearchesBox)) {
if (d->m_searchResults.size() >= MAX_SEARCH_HISTORY) {
if (d->m_currentIndex >= d->m_recentSearchesBox->count() - 1) {
// temporarily set the index to the last but one existing
d->m_currentIndex = d->m_recentSearchesBox->count() - 2;
}
d->m_searchResultWidgets.last()->notifyVisibilityChanged(false);
// widget first, because that might send interesting signals to SearchResult
delete d->m_searchResultWidgets.takeLast();
delete d->m_searchResults.takeLast();
d->m_recentSearchesBox->removeItem(d->m_recentSearchesBox->count() - 1);
}
d->m_searchResultWidgets.last()->notifyVisibilityChanged(false);
// widget first, because that might send interesting signals to SearchResult
delete d->m_searchResultWidgets.takeLast();
delete d->m_searchResults.takeLast();
d->m_recentSearchesBox->removeItem(d->m_recentSearchesBox->count()-1);
d->m_recentSearchesBox->insertItem(1, tr("%1 %2").arg(label, searchTerm));
}
auto widget = new SearchResultWidget;
connect(widget, &SearchResultWidget::filterInvalidated, this, [this, widget] {
@@ -532,7 +530,6 @@ SearchResult *SearchResultWindow::startNewSearch(const QString &label,
widget->setInfo(label, toolTip, searchTerm);
auto result = new SearchResult(widget);
d->m_searchResults.prepend(result);
d->m_recentSearchesBox->insertItem(1, tr("%1 %2").arg(label, searchTerm));
if (d->m_currentIndex > 0)
++d->m_currentIndex; // so setCurrentIndex still knows about the right "currentIndex" and its widget
d->setCurrentIndexWithFocus(1);
@@ -544,8 +541,10 @@ SearchResult *SearchResultWindow::startNewSearch(const QString &label,
*/
void SearchResultWindow::clearContents()
{
for (int i = d->m_recentSearchesBox->count() - 1; i > 0 /* don't want i==0 */; --i)
d->m_recentSearchesBox->removeItem(i);
if (QTC_GUARD(d->m_recentSearchesBox)) {
for (int i = d->m_recentSearchesBox->count() - 1; i > 0 /* don't want i==0 */; --i)
d->m_recentSearchesBox->removeItem(i);
}
foreach (Internal::SearchResultWidget *widget, d->m_searchResultWidgets)
widget->notifyVisibilityChanged(false);
qDeleteAll(d->m_searchResultWidgets);
@@ -642,6 +641,29 @@ void SearchResultWindowPrivate::updateFilterButton()
&& m_searchResultWidgets.at(visibleSearchIndex())->hasFilter());
}
QList<QWidget *> SearchResultWindowPrivate::toolBarWidgets()
{
if (!m_historyLabel)
m_historyLabel = new QLabel(tr("History:"));
if (!m_recentSearchesBox) {
m_recentSearchesBox = new QComboBox;
m_recentSearchesBox->setProperty("drawleftborder", true);
m_recentSearchesBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
m_recentSearchesBox->addItem(tr("New Search"));
connect(m_recentSearchesBox,
QOverload<int>::of(&QComboBox::activated),
this,
&SearchResultWindowPrivate::setCurrentIndexWithFocus);
}
return {m_expandCollapseButton,
m_filterButton,
m_newSearchButton,
m_spacer,
m_historyLabel,
m_spacer2,
m_recentSearchesBox};
}
/*!
\internal
*/

View File

@@ -684,7 +684,7 @@ Toolchains KitDetectorPrivate::autoDetectToolChains()
emit q->logOutput('\n' + tr("Searching toolchains..."));
for (ToolChainFactory *factory : factories) {
emit q->logOutput(tr("Searching toolchains of type %1").arg(factory->displayName()));
const ToolchainDetector detector(alreadyKnown, m_device);
const ToolchainDetector detector(alreadyKnown, m_device, m_searchPaths);
const Toolchains newToolChains = factory->autoDetect(detector);
for (ToolChain *toolChain : newToolChains) {
emit q->logOutput(tr("Found \"%1\"").arg(toolChain->compilerCommand().toUserOutput()));
@@ -1495,6 +1495,12 @@ QByteArray DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) cons
QTC_ASSERT(m_shell && m_shell->isRunning(), return {});
QMutexLocker l(&m_shellMutex);
m_shell->readAllStandardOutput(); // clean possible left-overs
const QByteArray oldError = m_shell->readAllStandardError(); // clean possible left-overs
if (!oldError.isEmpty()) {
LOG("Unexpected old stderr: " << oldError);
QTC_CHECK(false);
}
const QByteArray markerWithNewLine("___QC_DOCKER_" + randomHex() + "_OUTPUT_MARKER___\n");
m_shell->write(cmd.toUserOutput().toUtf8() + "\necho -n \"" + markerWithNewLine + "\"\n");
QByteArray output;
@@ -1506,6 +1512,11 @@ QByteArray DockerDevicePrivate::outputForRunInShell(const CommandLine &cmd) cons
LOG("Run command in shell:" << cmd.toUserOutput() << "output size:" << output.size());
if (QTC_GUARD(output.endsWith(markerWithNewLine)))
output.chop(markerWithNewLine.size());
const QByteArray currentError = m_shell->readAllStandardError();
if (!currentError.isEmpty()) {
LOG("Unexpected current stderr: " << currentError);
QTC_CHECK(false);
}
return output;
}

View File

@@ -365,7 +365,7 @@ static ToolChain *iarToolChain(const FilePath &path, Id language)
== BareMetal::Constants::IAREW_TOOLCHAIN_TYPEID;
});
if (iarFactory) {
Toolchains detected = iarFactory->autoDetect(ToolchainDetector({}, {}));
Toolchains detected = iarFactory->autoDetect(ToolchainDetector({}, {}, {}));
if (detected.isEmpty())
detected = iarFactory->detectForImport({path, language});
for (auto tc : detected) {

View File

@@ -1090,10 +1090,11 @@ Toolchains GccToolChainFactory::detectForImport(const ToolChainDescription &tcd)
return {};
}
static FilePaths findCompilerCandidates(const IDevice::ConstPtr &device,
static FilePaths findCompilerCandidates(const ToolchainDetector &detector,
const QString &compilerName,
bool detectVariants)
{
const IDevice::ConstPtr device = detector.device;
const QFileInfo fi(compilerName);
if (device.isNull() && fi.isAbsolute() && fi.isFile())
return {FilePath::fromString(compilerName)};
@@ -1119,7 +1120,9 @@ static FilePaths findCompilerCandidates(const IDevice::ConstPtr &device,
if (!device.isNull()) {
// FIXME: Merge with block below
FilePaths searchPaths = device->systemEnvironment().path();
FilePaths searchPaths = detector.searchPaths;
if (searchPaths.isEmpty())
searchPaths = device->systemEnvironment().path();
for (const FilePath &deviceDir : qAsConst(searchPaths)) {
static const QRegularExpression regexp(binaryRegexp);
const auto callBack = [&compilerPaths, compilerName](const FilePath &candidate) {
@@ -1135,16 +1138,19 @@ static FilePaths findCompilerCandidates(const IDevice::ConstPtr &device,
}
} else {
// The normal, local host case.
FilePaths searchPaths = Environment::systemEnvironment().path();
searchPaths << gnuSearchPathsFromRegistry();
searchPaths << atmelSearchPathsFromRegistry();
searchPaths << renesasRl78SearchPathsFromRegistry();
if (HostOsInfo::isAnyUnixHost()) {
FilePath ccachePath = "/usr/lib/ccache/bin";
if (!ccachePath.exists())
ccachePath = "/usr/lib/ccache";
if (ccachePath.exists() && !searchPaths.contains(ccachePath))
searchPaths << ccachePath;
FilePaths searchPaths = detector.searchPaths;
if (searchPaths.isEmpty()) {
searchPaths = Environment::systemEnvironment().path();
searchPaths << gnuSearchPathsFromRegistry();
searchPaths << atmelSearchPathsFromRegistry();
searchPaths << renesasRl78SearchPathsFromRegistry();
if (HostOsInfo::isAnyUnixHost()) {
FilePath ccachePath = "/usr/lib/ccache/bin";
if (!ccachePath.exists())
ccachePath = "/usr/lib/ccache";
if (ccachePath.exists() && !searchPaths.contains(ccachePath))
searchPaths << ccachePath;
}
}
for (const FilePath &dir : qAsConst(searchPaths)) {
static const QRegularExpression regexp(binaryRegexp);
@@ -1173,7 +1179,7 @@ Toolchains GccToolChainFactory::autoDetectToolchains(
const ToolchainChecker &checker) const
{
const FilePaths compilerPaths =
findCompilerCandidates(detector.device, compilerName, detectVariants == DetectVariants::Yes);
findCompilerCandidates(detector, compilerName, detectVariants == DetectVariants::Yes);
Toolchains existingCandidates = filtered(detector.alreadyKnown,
[language](const ToolChain *tc) { return tc->language() == language; });
Toolchains result;
@@ -1748,7 +1754,7 @@ Toolchains ClangToolChainFactory::autoDetect(const ToolchainDetector &detector)
const FilePath clang = compilerPath.parentDir().pathAppended("clang").withExecutableSuffix();
tcs.append(autoDetectToolchains(clang.toString(), DetectVariants::No,
Constants::C_LANGUAGE_ID, Constants::CLANG_TOOLCHAIN_TYPEID,
ToolchainDetector(known, detector.device)));
ToolchainDetector(known, detector.device, detector.searchPaths)));
}
return tcs;

View File

@@ -673,8 +673,10 @@ void ToolChainFactory::setUserCreatable(bool userCreatable)
m_userCreatable = userCreatable;
}
ToolchainDetector::ToolchainDetector(const Toolchains &alreadyKnown, const IDevice::ConstPtr &device)
: alreadyKnown(alreadyKnown), device(device)
ToolchainDetector::ToolchainDetector(const Toolchains &alreadyKnown,
const IDevice::ConstPtr &device,
const FilePaths &searchPaths)
: alreadyKnown(alreadyKnown), device(device), searchPaths(searchPaths)
{}
BadToolchain::BadToolchain(const Utils::FilePath &filePath)

View File

@@ -250,13 +250,16 @@ public:
class PROJECTEXPLORER_EXPORT ToolchainDetector
{
public:
ToolchainDetector(const Toolchains &alreadyKnown, const IDevice::ConstPtr &device);
ToolchainDetector(const Toolchains &alreadyKnown,
const IDevice::ConstPtr &device,
const Utils::FilePaths &searchPaths);
bool isBadToolchain(const Utils::FilePath &toolchain) const;
void addBadToolchain(const Utils::FilePath &toolchain) const;
const Toolchains alreadyKnown;
const IDevice::ConstPtr device;
const Utils::FilePaths searchPaths; // If empty use device path and/or magic.
};
class PROJECTEXPLORER_EXPORT ToolChainFactory

View File

@@ -412,7 +412,7 @@ void ToolChainOptionsWidget::redetectToolchains()
QSet<ToolChain *> toDelete;
ToolChainManager::resetBadToolchains();
for (ToolChainFactory *f : ToolChainFactory::allToolChainFactories()) {
const ToolchainDetector detector(knownTcs, {}); // FIXME: Pass device.
const ToolchainDetector detector(knownTcs, {}, {}); // FIXME: Pass device and search paths
for (ToolChain * const tc : f->autoDetect(detector)) {
if (knownTcs.contains(tc) || toDelete.contains(tc))
continue;

View File

@@ -205,7 +205,7 @@ Toolchains ToolChainSettingsAccessor::restoreToolChains(QWidget *parent) const
= Utils::filtered(userFileTcs, &ToolChain::isAutoDetected);
// FIXME: Use real device?
const Toolchains autodetectedTcs =
autoDetectToolChains(ToolchainDetector(autodetectedUserFileTcs, {}));
autoDetectToolChains(ToolchainDetector(autodetectedUserFileTcs, {}, {}));
// merge tool chains and register those that we need to keep:
const ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs);

View File

@@ -213,34 +213,38 @@ void AssetsLibraryWidget::handleAddAsset()
addResources({});
}
void AssetsLibraryWidget::handleExtFilesDrop(const QStringList &filesPaths, const QString &targetDirPath)
void AssetsLibraryWidget::handleExtFilesDrop(const QStringList &simpleFilesPaths,
const QStringList &complexFilesPaths,
const QString &targetDirPath)
{
QStringList assetPaths;
QStringList otherPaths; // as of now 3D models, and 3D Studio presentations
std::tie(assetPaths, otherPaths) = Utils::partition(filesPaths, [](const QString &path) {
QString suffix = "*." + path.split('.').last().toLower();
return AssetsLibraryModel::supportedSuffixes().contains(suffix);
});
AddFilesResult result = ModelNodeOperations::addFilesToProject(assetPaths, targetDirPath);
if (result == AddFilesResult::Failed) {
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
tr("Could not add %1 to project.")
.arg(filesPaths.join(' ')));
if (!simpleFilesPaths.isEmpty()) {
if (targetDirPath.isEmpty()) {
addResources(simpleFilesPaths);
} else {
AddFilesResult result = ModelNodeOperations::addFilesToProject(simpleFilesPaths,
targetDirPath);
if (result == AddFilesResult::Failed) {
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
tr("Could not add %1 to project.")
.arg(simpleFilesPaths.join(' ')));
}
}
}
if (!otherPaths.empty())
addResources(otherPaths);
if (!complexFilesPaths.empty())
addResources(complexFilesPaths);
}
QSet<QString> AssetsLibraryWidget::supportedDropSuffixes()
QSet<QString> AssetsLibraryWidget::supportedAssetSuffixes(bool complex)
{
const QList<AddResourceHandler> handlers = QmlDesignerPlugin::instance()->viewManager()
.designerActionManager().addResourceHandler();
QSet<QString> suffixes;
for (const AddResourceHandler &handler : handlers)
suffixes.insert(handler.filter);
for (const AddResourceHandler &handler : handlers) {
if (AssetsLibraryModel::supportedSuffixes().contains(handler.filter) != complex)
suffixes.insert(handler.filter);
}
return suffixes;
}

View File

@@ -80,8 +80,10 @@ public:
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
Q_INVOKABLE void handleAddAsset();
Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText);
Q_INVOKABLE void handleExtFilesDrop(const QStringList &filesPaths, const QString &targetDirPath);
Q_INVOKABLE QSet<QString> supportedDropSuffixes();
Q_INVOKABLE void handleExtFilesDrop(const QStringList &simpleFilesPaths,
const QStringList &complexFilesPaths,
const QString &targetDirPath = {});
Q_INVOKABLE QSet<QString> supportedAssetSuffixes(bool complex);
signals:
void itemActivated(const QString &itemName);

View File

@@ -360,9 +360,9 @@ void Edit3DView::createEdit3DActions()
m_showParticleEmitterAction = new Edit3DAction(
QmlDesigner::Constants::EDIT3D_EDIT_SHOW_PARTICLE_EMITTER, View3DActionCommand::ShowParticleEmitter,
QCoreApplication::translate("ShowParticleEmitterAction", "Always Show Particle Emitters"),
QCoreApplication::translate("ShowParticleEmitterAction", "Always Show Particle Emitters And Attractors"),
QKeySequence(Qt::Key_M), true, false, {}, {}, nullptr,
QCoreApplication::translate("ShowParticleEmitterAction", "Toggle between always showing the particle emitter visualization and only showing it when the emitter is selected."));
QCoreApplication::translate("ShowParticleEmitterAction", "Toggle between always showing the particle emitter and attractor visualizations and only showing them when the emitter or attractor is selected."));
SelectionContextOperation resetTrigger = [this](const SelectionContext &) {
m_particlesPlayAction->action()->setEnabled(particlemode);

View File

@@ -170,6 +170,8 @@ private: // functions
NodeInstance loadNode(const ModelNode &node);
void clearErrors();
void removeAllInstanceNodeRelationships();
void removeRecursiveChildRelationship(const ModelNode &removedNode);

View File

@@ -326,10 +326,17 @@ void NodeInstanceView::endPuppetTransaction()
}
}
void NodeInstanceView::clearErrors()
{
for (NodeInstance &instance : instances()) {
instance.setError({});
}
}
void NodeInstanceView::restartProcess()
{
if (rootNodeInstance().isValid())
rootNodeInstance().setError({});
clearErrors();
emitInstanceErrorChange({});
emitDocumentMessage({}, {});
@@ -556,10 +563,11 @@ void NodeInstanceView::nodeReparented(const ModelNode &node, const NodeAbstractP
m_nodeInstanceServer->reparentInstances(
createReparentInstancesCommand(node, newPropertyParent, oldPropertyParent));
// Reset puppet when particle emitter is reparented to work around issue in
// Reset puppet when particle emitter/affector is reparented to work around issue in
// autodetecting the particle system it belongs to. QTBUG-101157
if (node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D")
&& node.property("system").toBindingProperty().expression().isEmpty()) {
if ((node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D")
|| node.isSubclassOf("QtQuick.Particles3D.Affector3D"))
&& node.property("system").toBindingProperty().expression().isEmpty()) {
resetPuppet();
}
}
@@ -957,6 +965,8 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
}
}
clearErrors();
nodeList = filterNodesForSkipItems(nodeList);
QList<VariantProperty> variantPropertyList;

View File

@@ -767,12 +767,16 @@ NodeMetaInfoPrivate::NodeMetaInfoPrivate(Model *model, TypeName type, int maj, i
const ObjectValue *objectValue = getObjectValue();
if (objectValue) {
const CppComponentValue *qmlValue = value_cast<CppComponentValue>(objectValue);
if (qmlValue) {
if (m_majorVersion == -1 && m_minorVersion == -1) {
m_majorVersion = qmlValue->componentVersion().majorVersion();
m_minorVersion = qmlValue->componentVersion().minorVersion();
m_qualfiedTypeName = qmlValue->moduleName().toUtf8() + '.' + qmlValue->className().toUtf8();
} else if (m_majorVersion == qmlValue->componentVersion().majorVersion() && m_minorVersion == qmlValue->componentVersion().minorVersion()) {
m_qualfiedTypeName = qmlValue->moduleName().toUtf8() + '.'
+ qmlValue->className().toUtf8();
} else if (m_majorVersion == qmlValue->componentVersion().majorVersion()
&& m_minorVersion == qmlValue->componentVersion().minorVersion()) {
m_qualfiedTypeName = qmlValue->moduleName().toUtf8() + '.' + qmlValue->className().toUtf8();
} else {
return;
@@ -780,10 +784,16 @@ NodeMetaInfoPrivate::NodeMetaInfoPrivate(Model *model, TypeName type, int maj, i
} else {
m_isFileComponent = true;
const Imports *imports = context()->imports(document());
ImportInfo importInfo = imports->info(lookupNameComponent().constLast(), context().data());
if (importInfo.isValid() && importInfo.type() == ImportType::Library) {
m_majorVersion = importInfo.version().majorVersion();
m_minorVersion = importInfo.version().minorVersion();
const ImportInfo importInfo = imports->info(lookupNameComponent().constLast(), context().data());
if (importInfo.isValid()) {
if (importInfo.type() == ImportType::Library) {
m_majorVersion = importInfo.version().majorVersion();
m_minorVersion = importInfo.version().minorVersion();
}
bool prepandName = (importInfo.type() == ImportType::Library || importInfo.type() == ImportType::Directory)
&& !m_qualfiedTypeName.contains('.');
if (prepandName)
m_qualfiedTypeName.prepend(importInfo.name().toUtf8() + '.');
}
}
m_objectValue = objectValue;

View File

@@ -260,7 +260,9 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings)
#else
const auto showDebugSettings = settings.value(DesignerSettingsKey::SHOW_DEBUG_SETTINGS).toBool();
#endif
m_ui.debugGroupBox->setVisible(!standaloneMode || showDebugSettings);
const bool showAdvancedFeatures = !standaloneMode || showDebugSettings;
m_ui.emulationGroupBox->setVisible(showAdvancedFeatures);
m_ui.debugGroupBox->setVisible(showAdvancedFeatures);
m_ui.featureTimelineEditorCheckBox->setVisible(standaloneMode);
}

View File

@@ -95,7 +95,11 @@ void FileSystemAccessTest::initTestCase()
QVERIFY(!newDev.isNull());
devMgr->addDevice(newDev);
}
if (filePath.exists()) // Do initial cleanup after possible leftovers from previously failed test
QVERIFY(filePath.removeRecursively());
QVERIFY(!filePath.exists());
QVERIFY(filePath.createDir());
QVERIFY(filePath.exists());
}
void FileSystemAccessTest::cleanupTestCase()
@@ -106,7 +110,43 @@ void FileSystemAccessTest::cleanupTestCase()
QVERIFY(baseFilePath().removeRecursively());
}
void FileSystemAccessTest::testDirStatuses()
void FileSystemAccessTest::testCreateRemoteFile_data()
{
QTest::addColumn<QByteArray>("data");
QTest::newRow("Spaces") << QByteArray("Line with spaces");
QTest::newRow("Newlines") << QByteArray("Some \n\n newlines \n");
QTest::newRow("Carriage return") << QByteArray("Line with carriage \r return");
QTest::newRow("Tab") << QByteArray("Line with \t tab");
QTest::newRow("Apostrophe") << QByteArray("Line with apostrophe's character");
QTest::newRow("Quotation marks") << QByteArray("Line with \"quotation marks\"");
QTest::newRow("Backslash 1") << QByteArray("Line with \\ backslash");
QTest::newRow("Backslash 2") << QByteArray("Line with \\\" backslash");
QTest::newRow("Command output") << QByteArray("The date is: $(date +%D)");
const int charSize = sizeof(char) * 0x100;
QByteArray charString(charSize, Qt::Uninitialized);
char *data = charString.data();
for (int c = 0; c < charSize; ++c)
data[c] = c;
QTest::newRow("All Characters") << charString;
}
void FileSystemAccessTest::testCreateRemoteFile()
{
QFETCH(QByteArray, data);
const FilePath testFilePath = baseFilePath() / "test_file";
QVERIFY(!testFilePath.exists());
QVERIFY(testFilePath.writeFileContents(data));
QVERIFY(testFilePath.exists());
QCOMPARE(testFilePath.fileContents(), data);
QVERIFY(testFilePath.removeFile());
QVERIFY(!testFilePath.exists());
}
void FileSystemAccessTest::testDirStatus()
{
FilePath filePath = baseFilePath();
QVERIFY(filePath.exists());
@@ -142,7 +182,7 @@ void FileSystemAccessTest::testBytesAvailable()
void FileSystemAccessTest::testFileActions()
{
FilePath testFilePath = createFile("test");
const FilePath testFilePath = createFile("test");
QVERIFY(testFilePath.exists());
QVERIFY(testFilePath.isFile());
@@ -153,15 +193,17 @@ void FileSystemAccessTest::testFileActions()
QVERIFY(testFilePath.isReadableFile());
QVERIFY(testFilePath.isExecutableFile());
QByteArray content("Test");
const QByteArray content("Test");
testFilePath.writeFileContents(content);
// ToDo: remove ".contains", make fileContents exact equal content
QVERIFY(testFilePath.fileContents().contains(content));
QCOMPARE(testFilePath.fileContents(), content);
QVERIFY(testFilePath.renameFile(baseFilePath() / "test1"));
const FilePath newTestFilePath = baseFilePath() / "test1";
// It is Ok that FilePath doesn't change itself after rename.
FilePath newTestFilePath = baseFilePath() / "test1";
// FilePath::renameFile() is a const method!
QVERIFY(testFilePath.renameFile(newTestFilePath));
QVERIFY(!testFilePath.exists());
QVERIFY(newTestFilePath.exists());
QCOMPARE(newTestFilePath.fileContents(), content);
QVERIFY(!testFilePath.removeFile());
QVERIFY(newTestFilePath.exists());
QVERIFY(newTestFilePath.removeFile());

View File

@@ -45,12 +45,15 @@ class FileSystemAccessTest : public QObject
private slots:
void initTestCase();
void cleanupTestCase();
void testDirStatuses();
void testCreateRemoteFile_data();
void testCreateRemoteFile();
void testDirStatus();
void testBytesAvailable();
void testFileActions();
void cleanupTestCase();
private:
TestLinuxDeviceFactory m_testLinuxDeviceFactory;
bool m_skippedAtWhole = false;

View File

@@ -232,11 +232,14 @@ public:
bool runInShell(const CommandLine &cmd, const QByteArray &data = {})
{
QTC_ASSERT(m_shell, return false);
const QByteArray prefix = !data.isEmpty() ? QByteArray("echo " + data + " | ")
: QByteArray("");
QTC_CHECK(m_shell->readAllStandardOutput().isNull()); // clean possible left-overs
m_shell->readAllStandardOutput(); // clean possible left-overs
m_shell->write(prefix + cmd.toUserOutput().toUtf8() + "\necho $?\n");
const QByteArray prefix = !data.isEmpty()
? QByteArray("echo '" + data.toBase64() + "' | base64 -d | ") : QByteArray("");
const QByteArray suffix = QByteArray(" > /dev/null 2>&1\necho $?\n");
const QByteArray command = prefix + cmd.toUserOutput().toUtf8() + suffix;
m_shell->write(command);
DEBUG("RUN1 " << cmd.toUserOutput());
m_shell->waitForReadyRead();
const QByteArray output = m_shell->readAllStandardOutput();
@@ -244,18 +247,19 @@ public:
bool ok = false;
const int result = output.toInt(&ok);
LOG("Run command in shell:" << cmd.toUserOutput() << "result: " << output << " ==>" << result);
return ok && result == 0;
QTC_ASSERT(ok, return false);
return !result;
}
QByteArray outputForRunInShell(const QString &cmd)
{
QTC_ASSERT(m_shell, return {});
QTC_CHECK(m_shell->readAllStandardOutput().isNull()); // clean possible left-overs
static int val = 0;
const QByteArray delim = QString::number(++val, 16).toUtf8();
DEBUG("RUN2 " << cmd);
m_shell->readAllStandardOutput(); // clean possible left-overs
const QByteArray marker = "___QTC___" + delim + "_OUTPUT_MARKER___";
DEBUG(" CMD: " << cmd.toUtf8() + "\necho " + marker + "\n");
m_shell->write(cmd.toUtf8() + "\necho " + marker + "\n");
@@ -342,11 +346,9 @@ LinuxDevice::LinuxDevice()
proc->start();
});
if (Utils::HostOsInfo::isAnyUnixHost()) {
addDeviceAction({tr("Open Remote Shell"), [](const IDevice::Ptr &device, QWidget *) {
device->openTerminal(Environment(), FilePath());
}});
}
addDeviceAction({tr("Open Remote Shell"), [](const IDevice::Ptr &device, QWidget *) {
device->openTerminal(Environment(), FilePath());
}});
}
LinuxDevice::~LinuxDevice()
@@ -734,9 +736,6 @@ QByteArray LinuxDevice::fileContents(const FilePath &filePath, qint64 limit, qin
bool LinuxDevice::writeFileContents(const FilePath &filePath, const QByteArray &data) const
{
QTC_ASSERT(handlesFile(filePath), return {});
// This following would be the generic Unix solution.
// But it doesn't pass input. FIXME: Why?
return d->runInShell({"dd", {"of=" + filePath.path()}}, data);
}

View File

@@ -158,7 +158,7 @@ void WebAssemblyToolChain::registerToolChains()
};
// Create new toolchains and register them
ToolchainDetector detector({}, {});
ToolchainDetector detector({}, {}, {});
const Toolchains toolchains = doAutoDetect(detector);
for (auto toolChain : toolchains)
ToolChainManager::registerToolChain(toolChain);