2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2022 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2022-04-06 10:15:29 +02:00
|
|
|
|
|
|
|
|
#include "dockerdevicewidget.h"
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
#include "dockerapi.h"
|
|
|
|
|
#include "dockerdevice.h"
|
|
|
|
|
#include "dockertr.h"
|
|
|
|
|
|
2022-05-02 16:02:53 +02:00
|
|
|
#include <utils/algorithm.h>
|
2023-01-10 10:21:56 +01:00
|
|
|
#include <utils/clangutils.h>
|
2022-04-28 16:15:46 +02:00
|
|
|
#include <utils/environment.h>
|
2022-04-06 10:15:29 +02:00
|
|
|
#include <utils/hostosinfo.h>
|
|
|
|
|
#include <utils/layoutbuilder.h>
|
2022-12-02 13:30:29 +01:00
|
|
|
#include <utils/pathchooser.h>
|
2022-04-28 16:15:46 +02:00
|
|
|
#include <utils/qtcassert.h>
|
2022-05-02 16:02:53 +02:00
|
|
|
#include <utils/utilsicons.h>
|
2022-04-06 10:15:29 +02:00
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
#include <QCheckBox>
|
2022-04-06 10:15:29 +02:00
|
|
|
#include <QComboBox>
|
2022-07-13 10:43:31 +02:00
|
|
|
#include <QPushButton>
|
|
|
|
|
#include <QTextBrowser>
|
|
|
|
|
#include <QToolButton>
|
2022-04-06 10:15:29 +02:00
|
|
|
|
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
namespace Docker::Internal {
|
2022-04-06 10:15:29 +02:00
|
|
|
|
|
|
|
|
DockerDeviceWidget::DockerDeviceWidget(const IDevice::Ptr &device)
|
|
|
|
|
: IDeviceWidget(device), m_kitItemDetector(device)
|
|
|
|
|
{
|
|
|
|
|
auto dockerDevice = device.dynamicCast<DockerDevice>();
|
|
|
|
|
QTC_ASSERT(dockerDevice, return);
|
|
|
|
|
|
2022-09-14 16:20:02 +02:00
|
|
|
m_data = dockerDevice->data();
|
2022-04-06 10:15:29 +02:00
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
auto repoLabel = new QLabel(Tr::tr("Repository:"));
|
2022-04-06 10:15:29 +02:00
|
|
|
m_repoLineEdit = new QLineEdit;
|
2022-09-14 16:20:02 +02:00
|
|
|
m_repoLineEdit->setText(m_data.repo);
|
2022-04-06 10:15:29 +02:00
|
|
|
m_repoLineEdit->setEnabled(false);
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
auto tagLabel = new QLabel(Tr::tr("Tag:"));
|
2022-04-06 10:15:29 +02:00
|
|
|
m_tagLineEdit = new QLineEdit;
|
2022-09-14 16:20:02 +02:00
|
|
|
m_tagLineEdit->setText(m_data.tag);
|
2022-04-06 10:15:29 +02:00
|
|
|
m_tagLineEdit->setEnabled(false);
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
auto idLabel = new QLabel(Tr::tr("Image ID:"));
|
2022-04-06 10:15:29 +02:00
|
|
|
m_idLineEdit = new QLineEdit;
|
2022-09-14 16:20:02 +02:00
|
|
|
m_idLineEdit->setText(m_data.imageId);
|
2022-04-06 10:15:29 +02:00
|
|
|
m_idLineEdit->setEnabled(false);
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
auto daemonStateLabel = new QLabel(Tr::tr("Daemon state:"));
|
2022-04-06 10:15:29 +02:00
|
|
|
m_daemonReset = new QToolButton;
|
2022-07-13 10:43:31 +02:00
|
|
|
m_daemonReset->setToolTip(Tr::tr("Clears detected daemon state. "
|
2022-04-06 10:15:29 +02:00
|
|
|
"It will be automatically re-evaluated next time access is needed."));
|
|
|
|
|
|
|
|
|
|
m_daemonState = new QLabel;
|
|
|
|
|
|
2022-04-05 11:43:56 +02:00
|
|
|
connect(DockerApi::instance(), &DockerApi::dockerDaemonAvailableChanged, this, [this]{
|
2022-04-06 10:15:29 +02:00
|
|
|
updateDaemonStateTexts();
|
|
|
|
|
});
|
|
|
|
|
|
2022-04-05 11:43:56 +02:00
|
|
|
updateDaemonStateTexts();
|
|
|
|
|
|
|
|
|
|
connect(m_daemonReset, &QToolButton::clicked, this, [] {
|
|
|
|
|
DockerApi::recheckDockerDaemon();
|
|
|
|
|
});
|
|
|
|
|
|
2022-10-19 18:25:20 +02:00
|
|
|
m_keepEntryPoint = new QCheckBox(Tr::tr("Do not modify entry point"));
|
2022-09-14 16:43:39 +02:00
|
|
|
m_keepEntryPoint->setToolTip(
|
2022-10-19 18:25:20 +02:00
|
|
|
Tr::tr("Prevents modifying the entry point of the image. Enable only if "
|
2022-09-14 16:43:39 +02:00
|
|
|
"the image starts into a shell."));
|
|
|
|
|
m_keepEntryPoint->setChecked(m_data.keepEntryPoint);
|
|
|
|
|
m_keepEntryPoint->setEnabled(true);
|
|
|
|
|
|
|
|
|
|
connect(m_keepEntryPoint, &QCheckBox::toggled, this, [this, dockerDevice](bool on) {
|
|
|
|
|
m_data.keepEntryPoint = on;
|
|
|
|
|
dockerDevice->setData(m_data);
|
|
|
|
|
});
|
|
|
|
|
|
2022-11-17 13:56:28 +01:00
|
|
|
m_enableLldbFlags = new QCheckBox(Tr::tr("Enable flags needed for LLDB"));
|
|
|
|
|
m_enableLldbFlags->setToolTip(Tr::tr("Adds the following flags to the container: "
|
|
|
|
|
"--cap-add=SYS_PTRACE --security-opt seccomp=unconfined, "
|
|
|
|
|
"this is necessary to allow lldb to run"));
|
|
|
|
|
m_enableLldbFlags->setChecked(m_data.enableLldbFlags);
|
|
|
|
|
m_enableLldbFlags->setEnabled(true);
|
|
|
|
|
|
|
|
|
|
connect(m_enableLldbFlags, &QCheckBox::toggled, this, [this, dockerDevice](bool on) {
|
|
|
|
|
m_data.enableLldbFlags = on;
|
|
|
|
|
dockerDevice->setData(m_data);
|
|
|
|
|
});
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
m_runAsOutsideUser = new QCheckBox(Tr::tr("Run as outside user"));
|
|
|
|
|
m_runAsOutsideUser->setToolTip(Tr::tr("Uses user ID and group ID of the user running Qt Creator "
|
|
|
|
|
"in the docker container."));
|
2022-09-14 16:20:02 +02:00
|
|
|
m_runAsOutsideUser->setChecked(m_data.useLocalUidGid);
|
2022-10-13 14:56:22 +02:00
|
|
|
m_runAsOutsideUser->setEnabled(HostOsInfo::isAnyUnixHost());
|
2022-04-06 10:15:29 +02:00
|
|
|
|
2022-09-14 16:20:02 +02:00
|
|
|
connect(m_runAsOutsideUser, &QCheckBox::toggled, this, [this, dockerDevice](bool on) {
|
|
|
|
|
m_data.useLocalUidGid = on;
|
|
|
|
|
dockerDevice->setData(m_data);
|
2022-04-06 10:15:29 +02:00
|
|
|
});
|
|
|
|
|
|
2022-12-02 13:30:29 +01:00
|
|
|
auto clangDLabel = new QLabel(Tr::tr("Clangd Executable:"));
|
|
|
|
|
|
|
|
|
|
m_clangdExecutable = new PathChooser();
|
|
|
|
|
m_clangdExecutable->setExpectedKind(PathChooser::ExistingCommand);
|
|
|
|
|
m_clangdExecutable->setHistoryCompleter("Docker.ClangdExecutable.History");
|
|
|
|
|
m_clangdExecutable->setAllowPathFromDevice(true);
|
|
|
|
|
m_clangdExecutable->setFilePath(m_data.clangdExecutable);
|
2023-01-10 10:21:56 +01:00
|
|
|
m_clangdExecutable->setValidationFunction(
|
|
|
|
|
[chooser = m_clangdExecutable](FancyLineEdit *, QString *error) {
|
|
|
|
|
return Utils::checkClangdVersion(chooser->filePath(), error);
|
|
|
|
|
});
|
2022-12-02 13:30:29 +01:00
|
|
|
|
2022-12-07 23:47:15 +01:00
|
|
|
connect(m_clangdExecutable, &PathChooser::rawPathChanged, this, [this, dockerDevice] {
|
2022-12-02 13:30:29 +01:00
|
|
|
m_data.clangdExecutable = m_clangdExecutable->filePath();
|
|
|
|
|
dockerDevice->setData(m_data);
|
|
|
|
|
});
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
auto pathListLabel = new InfoLabel(Tr::tr("Paths to mount:"));
|
|
|
|
|
pathListLabel->setAdditionalToolTip(Tr::tr("Source directory list should not be empty."));
|
2022-04-06 10:15:29 +02:00
|
|
|
|
|
|
|
|
m_pathsListEdit = new PathListEditor;
|
2022-07-13 10:43:31 +02:00
|
|
|
m_pathsListEdit->setPlaceholderText(Tr::tr("Host directories to mount into the container"));
|
|
|
|
|
m_pathsListEdit->setToolTip(Tr::tr("Maps paths in this list one-to-one to the "
|
|
|
|
|
"docker container."));
|
2022-09-14 16:20:02 +02:00
|
|
|
m_pathsListEdit->setPathList(m_data.mounts);
|
2022-07-26 16:00:30 +02:00
|
|
|
m_pathsListEdit->setMaximumHeight(100);
|
|
|
|
|
m_pathsListEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
2022-04-06 10:15:29 +02:00
|
|
|
|
2022-04-07 09:01:21 +02:00
|
|
|
auto markupMounts = [this, pathListLabel] {
|
2022-04-06 10:15:29 +02:00
|
|
|
const bool isEmpty = m_pathsListEdit->pathList().isEmpty();
|
2022-04-07 09:01:21 +02:00
|
|
|
pathListLabel->setType(isEmpty ? InfoLabel::Warning : InfoLabel::None);
|
2022-04-06 10:15:29 +02:00
|
|
|
};
|
|
|
|
|
markupMounts();
|
|
|
|
|
|
2022-09-14 16:20:02 +02:00
|
|
|
connect(m_pathsListEdit, &PathListEditor::changed, this, [this, dockerDevice, markupMounts] {
|
|
|
|
|
m_data.mounts = m_pathsListEdit->pathList();
|
|
|
|
|
dockerDevice->setData(m_data);
|
2022-04-06 10:15:29 +02:00
|
|
|
markupMounts();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto logView = new QTextBrowser;
|
|
|
|
|
connect(&m_kitItemDetector, &KitDetector::logOutput,
|
|
|
|
|
logView, &QTextBrowser::append);
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
auto autoDetectButton = new QPushButton(Tr::tr("Auto-detect Kit Items"));
|
|
|
|
|
auto undoAutoDetectButton = new QPushButton(Tr::tr("Remove Auto-Detected Kit Items"));
|
|
|
|
|
auto listAutoDetectedButton = new QPushButton(Tr::tr("List Auto-Detected Kit Items"));
|
2022-04-06 10:15:29 +02:00
|
|
|
|
|
|
|
|
auto searchDirsComboBox = new QComboBox;
|
2022-07-13 10:43:31 +02:00
|
|
|
searchDirsComboBox->addItem(Tr::tr("Search in PATH"));
|
|
|
|
|
searchDirsComboBox->addItem(Tr::tr("Search in Selected Directories"));
|
2022-07-28 11:27:55 +02:00
|
|
|
searchDirsComboBox->addItem(Tr::tr("Search in PATH and Additional Directories"));
|
2022-04-06 10:15:29 +02:00
|
|
|
|
|
|
|
|
auto searchDirsLineEdit = new FancyLineEdit;
|
2022-04-07 09:01:21 +02:00
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
searchDirsLineEdit->setPlaceholderText(Tr::tr("Semicolon-separated list of directories"));
|
2022-04-06 10:15:29 +02:00
|
|
|
searchDirsLineEdit->setToolTip(
|
2022-07-13 10:43:31 +02:00
|
|
|
Tr::tr("Select the paths in the docker image that should be scanned for kit entries."));
|
2022-04-06 10:15:29 +02:00
|
|
|
searchDirsLineEdit->setHistoryCompleter("DockerMounts", true);
|
|
|
|
|
|
|
|
|
|
auto searchPaths = [searchDirsComboBox, searchDirsLineEdit, dockerDevice] {
|
|
|
|
|
FilePaths paths;
|
2022-07-28 11:27:55 +02:00
|
|
|
const int idx = searchDirsComboBox->currentIndex();
|
|
|
|
|
if (idx == 0 || idx == 2)
|
|
|
|
|
paths += dockerDevice->systemEnvironment().path();
|
|
|
|
|
if (idx == 1 || idx == 2) {
|
2022-04-06 10:15:29 +02:00
|
|
|
for (const QString &path : searchDirsLineEdit->text().split(';'))
|
|
|
|
|
paths.append(FilePath::fromString(path.trimmed()));
|
|
|
|
|
}
|
|
|
|
|
paths = Utils::transform(paths, [dockerDevice](const FilePath &path) {
|
2022-12-14 17:26:30 +01:00
|
|
|
return dockerDevice->filePath(path.path());
|
2022-04-06 10:15:29 +02:00
|
|
|
});
|
|
|
|
|
return paths;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
connect(autoDetectButton, &QPushButton::clicked, this,
|
|
|
|
|
[this, logView, dockerDevice, searchPaths] {
|
|
|
|
|
logView->clear();
|
|
|
|
|
dockerDevice->updateContainerAccess();
|
|
|
|
|
|
2023-02-09 08:20:01 +01:00
|
|
|
const FilePath clangdPath = dockerDevice->filePath("clangd")
|
|
|
|
|
.searchInPath({},
|
|
|
|
|
FilePath::AppendToPath,
|
|
|
|
|
[](const FilePath &clangd) {
|
|
|
|
|
return Utils::checkClangdVersion(clangd);
|
|
|
|
|
});
|
|
|
|
|
|
2022-12-02 13:30:29 +01:00
|
|
|
if (!clangdPath.isEmpty())
|
|
|
|
|
m_clangdExecutable->setFilePath(clangdPath);
|
|
|
|
|
|
2022-04-06 10:15:29 +02:00
|
|
|
m_kitItemDetector.autoDetect(dockerDevice->id().toString(), searchPaths());
|
|
|
|
|
|
2022-04-05 11:43:56 +02:00
|
|
|
if (DockerApi::instance()->dockerDaemonAvailable().value_or(false) == false)
|
2022-07-13 10:43:31 +02:00
|
|
|
logView->append(Tr::tr("Docker daemon appears to be not running."));
|
2022-04-06 10:15:29 +02:00
|
|
|
else
|
2022-07-13 10:43:31 +02:00
|
|
|
logView->append(Tr::tr("Docker daemon appears to be running."));
|
2023-04-06 10:42:28 +02:00
|
|
|
|
|
|
|
|
logView->append(Tr::tr("Detection complete."));
|
2022-04-06 10:15:29 +02:00
|
|
|
updateDaemonStateTexts();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
connect(undoAutoDetectButton, &QPushButton::clicked, this, [this, logView, device] {
|
|
|
|
|
logView->clear();
|
|
|
|
|
m_kitItemDetector.undoAutoDetect(device->id().toString());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
connect(listAutoDetectedButton, &QPushButton::clicked, this, [this, logView, device] {
|
|
|
|
|
logView->clear();
|
|
|
|
|
m_kitItemDetector.listAutoDetected(device->id().toString());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
using namespace Layouting;
|
|
|
|
|
|
2022-11-17 13:56:28 +01:00
|
|
|
// clang-format off
|
2022-12-06 13:46:08 +01:00
|
|
|
Column detectionControls {
|
|
|
|
|
Space(20),
|
|
|
|
|
Row {
|
|
|
|
|
Tr::tr("Search Locations:"),
|
|
|
|
|
searchDirsComboBox,
|
|
|
|
|
searchDirsLineEdit
|
|
|
|
|
},
|
|
|
|
|
Row {
|
|
|
|
|
autoDetectButton,
|
|
|
|
|
undoAutoDetectButton,
|
|
|
|
|
listAutoDetectedButton,
|
|
|
|
|
st,
|
|
|
|
|
},
|
|
|
|
|
Tr::tr("Detection log:"),
|
|
|
|
|
logView
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-06 10:15:29 +02:00
|
|
|
Form {
|
2022-07-22 18:54:04 +02:00
|
|
|
repoLabel, m_repoLineEdit, br,
|
|
|
|
|
tagLabel, m_tagLineEdit, br,
|
|
|
|
|
idLabel, m_idLineEdit, br,
|
|
|
|
|
daemonStateLabel, m_daemonReset, m_daemonState, br,
|
|
|
|
|
m_runAsOutsideUser, br,
|
2022-09-14 16:43:39 +02:00
|
|
|
m_keepEntryPoint, br,
|
2022-11-17 13:56:28 +01:00
|
|
|
m_enableLldbFlags, br,
|
2022-12-02 13:30:29 +01:00
|
|
|
clangDLabel, m_clangdExecutable, br,
|
2022-04-06 10:15:29 +02:00
|
|
|
Column {
|
2022-04-07 09:01:21 +02:00
|
|
|
pathListLabel,
|
2022-04-06 10:15:29 +02:00
|
|
|
m_pathsListEdit,
|
2022-07-22 18:54:04 +02:00
|
|
|
}, br,
|
2022-12-06 13:46:08 +01:00
|
|
|
(dockerDevice->isAutoDetected() ? Column {} : std::move(detectionControls)),
|
2023-05-02 12:51:03 +02:00
|
|
|
noMargin,
|
|
|
|
|
}.attachTo(this);
|
2022-11-17 13:56:28 +01:00
|
|
|
// clang-format on
|
2022-04-06 10:15:29 +02:00
|
|
|
|
|
|
|
|
searchDirsLineEdit->setVisible(false);
|
|
|
|
|
auto updateDirectoriesLineEdit = [searchDirsLineEdit](int index) {
|
2022-07-28 11:27:55 +02:00
|
|
|
searchDirsLineEdit->setVisible(index == 1 || index == 2);
|
|
|
|
|
if (index == 1 || index == 2)
|
2022-04-06 10:15:29 +02:00
|
|
|
searchDirsLineEdit->setFocus();
|
|
|
|
|
};
|
2022-07-19 23:43:58 +02:00
|
|
|
QObject::connect(searchDirsComboBox, &QComboBox::activated, this, updateDirectoriesLineEdit);
|
2022-04-06 10:15:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DockerDeviceWidget::updateDaemonStateTexts()
|
|
|
|
|
{
|
2022-08-26 10:30:00 +02:00
|
|
|
std::optional<bool> daemonState = DockerApi::instance()->dockerDaemonAvailable();
|
2022-04-06 10:15:29 +02:00
|
|
|
if (!daemonState.has_value()) {
|
|
|
|
|
m_daemonReset->setIcon(Icons::INFO.icon());
|
2022-07-13 10:43:31 +02:00
|
|
|
m_daemonState->setText(Tr::tr("Daemon state not evaluated."));
|
2022-04-06 10:15:29 +02:00
|
|
|
} else if (daemonState.value()) {
|
|
|
|
|
m_daemonReset->setIcon(Icons::OK.icon());
|
2022-07-13 10:43:31 +02:00
|
|
|
m_daemonState->setText(Tr::tr("Docker daemon running."));
|
2022-04-06 10:15:29 +02:00
|
|
|
} else {
|
|
|
|
|
m_daemonReset->setIcon(Icons::CRITICAL.icon());
|
2022-07-13 10:43:31 +02:00
|
|
|
m_daemonState->setText(Tr::tr("Docker daemon not running."));
|
2022-04-06 10:15:29 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-13 10:43:31 +02:00
|
|
|
} // Docker::Internal
|