forked from qt-creator/qt-creator
Docker: Improve error output when bridge fails to start
Change-Id: I86d9d3972c483d21cd2ff64d3581b518e6b0a819 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -68,22 +68,31 @@ expected_str<void> FileAccess::deployAndInit(
|
||||
|
||||
qCDebug(faLog) << "Found dd on remote host:" << *whichDD;
|
||||
|
||||
const auto unameOs = run({remoteRootPath.withNewPath("uname"), {"-s"}});
|
||||
if (!unameOs)
|
||||
const expected_str<QString> unameOs = run({remoteRootPath.withNewPath("uname"), {"-s"}});
|
||||
if (!unameOs) {
|
||||
return make_unexpected(
|
||||
QString("Could not determine OS on remote host: %1").arg(unameOs.error()));
|
||||
}
|
||||
Utils::expected_str<OsType> osType = osTypeFromString(unameOs.value());
|
||||
if (!osType)
|
||||
return make_unexpected(osType.error());
|
||||
|
||||
qCDebug(faLog) << "Remote host OS:" << *unameOs;
|
||||
|
||||
const auto unameArch = run({remoteRootPath.withNewPath("uname"), {"-m"}});
|
||||
if (!unameArch)
|
||||
const expected_str<QString> unameArch = run({remoteRootPath.withNewPath("uname"), {"-m"}});
|
||||
if (!unameArch) {
|
||||
return make_unexpected(
|
||||
QString("Could not determine architecture on remote host: %1").arg(unameArch.error()));
|
||||
}
|
||||
|
||||
const Utils::expected_str<OsArch> osArch = osArchFromString(unameArch.value());
|
||||
if (!osArch)
|
||||
return make_unexpected(osArch.error());
|
||||
|
||||
qCDebug(faLog) << "Remote host architecture:" << *unameArch;
|
||||
|
||||
const Utils::expected_str<Utils::FilePath> cmdBridgePath = Client::getCmdBridgePath(
|
||||
osTypeFromString(unameOs.value()), osArchFromString(unameArch.value()), libExecPath);
|
||||
const Utils::expected_str<Utils::FilePath> cmdBridgePath
|
||||
= Client::getCmdBridgePath(*osType, *osArch, libExecPath);
|
||||
|
||||
if (!cmdBridgePath) {
|
||||
return make_unexpected(
|
||||
|
@@ -259,15 +259,19 @@ expected_str<QFuture<Environment>> Client::start()
|
||||
d->jobs.writeLocked()->map.insert(-1, [envPromise](QVariantMap map) {
|
||||
envPromise->start();
|
||||
QString type = map.value("Type").toString();
|
||||
QTC_CHECK(type == "environment");
|
||||
if (type == "environment") {
|
||||
OsType osType = osTypeFromString(map.value("OsType").toString());
|
||||
Environment env(map.value("Env").toStringList(), osType);
|
||||
expected_str<OsType> osType = osTypeFromString(map.value("OsType").toString());
|
||||
QTC_CHECK_EXPECTED(osType);
|
||||
Environment env(map.value("Env").toStringList(), osType.value_or(OsTypeLinux));
|
||||
envPromise->addResult(env);
|
||||
} else if (type == "error") {
|
||||
QString err = map.value("Error", QString{}).toString();
|
||||
qCWarning(clientLog) << "Error: " << err;
|
||||
envPromise->setException(std::make_exception_ptr(std::runtime_error(err.toStdString())));
|
||||
} else {
|
||||
qCWarning(clientLog) << "Unknown initial response type: " << type;
|
||||
envPromise->setException(
|
||||
std::make_exception_ptr(std::runtime_error("Unknown response type")));
|
||||
}
|
||||
|
||||
envPromise->finish();
|
||||
@@ -284,9 +288,11 @@ expected_str<QFuture<Environment>> Client::start()
|
||||
|
||||
connect(d->process, &Process::done, d->process, [this] {
|
||||
if (d->process->resultData().m_exitCode != 0) {
|
||||
qCWarning(clientLog).noquote() << d->process->resultData().m_errorString;
|
||||
qCWarning(clientLog).noquote() << d->process->readAllStandardError();
|
||||
qCWarning(clientLog).noquote() << d->process->readAllStandardOutput();
|
||||
qCWarning(clientLog)
|
||||
<< "Process exited with error code:" << d->process->resultData().m_exitCode
|
||||
<< "Error:" << d->process->errorString()
|
||||
<< "StandardError:" << d->process->readAllStandardError()
|
||||
<< "StandardOutput:" << d->process->readAllStandardOutput();
|
||||
}
|
||||
|
||||
auto j = d->jobs.writeLocked();
|
||||
|
@@ -31,7 +31,8 @@ bool HostOsInfo::m_useOverrideFileNameCaseSensitivity = false;
|
||||
|
||||
OsArch HostOsInfo::hostArchitecture()
|
||||
{
|
||||
static const OsArch arch = osArchFromString(QSysInfo::currentCpuArchitecture());
|
||||
static const OsArch arch
|
||||
= osArchFromString(QSysInfo::currentCpuArchitecture()).value_or(OsArchUnknown);
|
||||
return arch;
|
||||
}
|
||||
|
||||
|
@@ -3,6 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "expected.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -33,7 +36,7 @@ inline QString osTypeToString(OsType osType)
|
||||
}
|
||||
}
|
||||
|
||||
inline OsType osTypeFromString(const QString &string)
|
||||
inline Utils::expected_str<OsType> osTypeFromString(const QString &string)
|
||||
{
|
||||
if (string.compare("windows", Qt::CaseInsensitive) == 0)
|
||||
return OsTypeWindows;
|
||||
@@ -44,10 +47,11 @@ inline OsType osTypeFromString(const QString &string)
|
||||
return OsTypeMac;
|
||||
if (string.compare("other unix", Qt::CaseInsensitive) == 0)
|
||||
return OsTypeOtherUnix;
|
||||
return OsTypeOther;
|
||||
|
||||
return Utils::make_unexpected(QString::fromLatin1("Unknown os type: %1").arg(string));
|
||||
}
|
||||
|
||||
inline OsArch osArchFromString(const QString &architecture)
|
||||
inline Utils::expected_str<OsArch> osArchFromString(const QString &architecture)
|
||||
{
|
||||
if (architecture == QLatin1String("x86_64"))
|
||||
return OsArchAMD64;
|
||||
@@ -59,7 +63,8 @@ inline OsArch osArchFromString(const QString &architecture)
|
||||
return OsArchArm;
|
||||
if (architecture == QLatin1String("arm64") || architecture == QLatin1String("aarch64"))
|
||||
return OsArchArm64;
|
||||
return OsArchUnknown;
|
||||
|
||||
return Utils::make_unexpected(QString::fromLatin1("Unknown architecture: %1").arg(architecture));
|
||||
}
|
||||
|
||||
namespace OsSpecificAspects {
|
||||
|
@@ -313,7 +313,7 @@ public:
|
||||
QString repoAndTagEncoded() const { return deviceSettings->repoAndTagEncoded(); }
|
||||
QString dockerImageId() const { return deviceSettings->imageId(); }
|
||||
|
||||
QPair<Utils::OsType, Utils::OsArch> osTypeAndArch() const;
|
||||
expected_str<QPair<Utils::OsType, Utils::OsArch>> osTypeAndArch() const;
|
||||
|
||||
expected_str<Environment> environment();
|
||||
|
||||
@@ -332,6 +332,8 @@ public:
|
||||
void stopCurrentContainer();
|
||||
expected_str<void> fetchSystemEnviroment();
|
||||
|
||||
expected_str<FilePath> getCmdBridgePath() const;
|
||||
|
||||
std::optional<FilePath> clangdExecutable() const
|
||||
{
|
||||
if (deviceSettings->clangdExecutable().isEmpty())
|
||||
@@ -594,7 +596,22 @@ DockerDevice::DockerDevice(std::unique_ptr<DockerDeviceSettings> deviceSettings)
|
||||
: ProjectExplorer::IDevice(std::move(deviceSettings))
|
||||
, d(new DockerDevicePrivate(this))
|
||||
{
|
||||
setFileAccess([this]() -> DeviceFileAccess * {
|
||||
auto createBridgeFileAccess = [this]() -> expected_str<std::unique_ptr<DeviceFileAccess>> {
|
||||
expected_str<FilePath> cmdBridgePath = d->getCmdBridgePath();
|
||||
|
||||
if (!cmdBridgePath)
|
||||
return make_unexpected(cmdBridgePath.error());
|
||||
|
||||
auto fAccess = std::make_unique<DockerDeviceFileAccess>(d);
|
||||
expected_str<void> initResult = fAccess->init(
|
||||
rootPath().withNewPath("/tmp/_qtc_cmdbridge"));
|
||||
if (!initResult)
|
||||
return make_unexpected(initResult.error());
|
||||
|
||||
return fAccess;
|
||||
};
|
||||
|
||||
setFileAccess([this, createBridgeFileAccess]() -> DeviceFileAccess * {
|
||||
if (DeviceFileAccess *fileAccess = d->m_fileAccess.readLocked()->get())
|
||||
return fileAccess;
|
||||
|
||||
@@ -603,15 +620,16 @@ DockerDevice::DockerDevice(std::unique_ptr<DockerDeviceSettings> deviceSettings)
|
||||
if (*fileAccess)
|
||||
return fileAccess->get();
|
||||
|
||||
auto fAccess = std::make_unique<DockerDeviceFileAccess>(d);
|
||||
expected_str<void> initResult = fAccess->init(
|
||||
rootPath().withNewPath("/tmp/_qtc_cmdbridge"));
|
||||
QTC_CHECK_EXPECTED(initResult);
|
||||
if (initResult) {
|
||||
*fileAccess = std::move(fAccess);
|
||||
expected_str<std::unique_ptr<DeviceFileAccess>> fAccess = createBridgeFileAccess();
|
||||
|
||||
if (fAccess) {
|
||||
*fileAccess = std::move(*fAccess);
|
||||
return fileAccess->get();
|
||||
}
|
||||
|
||||
qCWarning(dockerDeviceLog) << "Failed to start CmdBridge:" << fAccess.error()
|
||||
<< ", falling back to slow direct access";
|
||||
|
||||
*fileAccess = std::make_unique<DockerFallbackFileAccess>(rootPath());
|
||||
return fileAccess->get();
|
||||
});
|
||||
@@ -835,13 +853,18 @@ expected_str<void> isValidMountInfo(const DockerDevicePrivate::MountPair &mi)
|
||||
return {};
|
||||
}
|
||||
|
||||
QStringList DockerDevicePrivate::createMountArgs() const
|
||||
expected_str<FilePath> DockerDevicePrivate::getCmdBridgePath() const
|
||||
{
|
||||
auto osAndArch = osTypeAndArch();
|
||||
if (!osAndArch)
|
||||
return make_unexpected(osAndArch.error());
|
||||
return CmdBridge::Client::getCmdBridgePath(
|
||||
osAndArch->first, osAndArch->second, Core::ICore::libexecPath());
|
||||
};
|
||||
|
||||
const Utils::expected_str<Utils::FilePath> cmdBridgePath = CmdBridge::Client::getCmdBridgePath(
|
||||
osAndArch.first, osAndArch.second, Core::ICore::libexecPath());
|
||||
|
||||
QStringList DockerDevicePrivate::createMountArgs() const
|
||||
{
|
||||
const Utils::expected_str<Utils::FilePath> cmdBridgePath = getCmdBridgePath();
|
||||
QTC_CHECK_EXPECTED(cmdBridgePath);
|
||||
|
||||
QStringList cmds;
|
||||
@@ -1325,7 +1348,7 @@ void DockerDeviceFactory::shutdownExistingDevices()
|
||||
}
|
||||
}
|
||||
|
||||
QPair<Utils::OsType, Utils::OsArch> DockerDevicePrivate::osTypeAndArch() const
|
||||
expected_str<QPair<Utils::OsType, Utils::OsArch>> DockerDevicePrivate::osTypeAndArch() const
|
||||
{
|
||||
Process proc;
|
||||
proc.setCommand(
|
||||
@@ -1333,13 +1356,21 @@ QPair<Utils::OsType, Utils::OsArch> DockerDevicePrivate::osTypeAndArch() const
|
||||
{"image", "inspect", repoAndTag(), "--format", "{{.Os}}\t{{.Architecture}}"}});
|
||||
proc.runBlocking();
|
||||
if (proc.result() != ProcessResult::FinishedWithSuccess)
|
||||
return {Utils::OsType::OsTypeOther, Utils::OsArch::OsArchUnknown};
|
||||
return make_unexpected(Tr::tr("Failed to inspect image: %1").arg(proc.allOutput()));
|
||||
|
||||
const QString out = proc.cleanedStdOut().trimmed();
|
||||
const QStringList parts = out.split('\t');
|
||||
if (parts.size() != 2)
|
||||
return {Utils::OsType::OsTypeOther, Utils::OsArch::OsArchUnknown};
|
||||
return {osTypeFromString(parts.at(0)), osArchFromString(parts.at(1))};
|
||||
return make_unexpected(Tr::tr("Could not parse image inspect output: %1").arg(out));
|
||||
|
||||
auto os = osTypeFromString(parts.at(0));
|
||||
auto arch = osArchFromString(parts.at(1));
|
||||
if (!os)
|
||||
return make_unexpected(os.error());
|
||||
if (!arch)
|
||||
return make_unexpected(arch.error());
|
||||
|
||||
return qMakePair(os.value(), arch.value());
|
||||
}
|
||||
|
||||
expected_str<Environment> DockerDevicePrivate::environment()
|
||||
|
@@ -500,7 +500,7 @@ void IDevice::fromMap(const Store &map)
|
||||
settings()->fromMap(map);
|
||||
|
||||
d->id = Id::fromSetting(map.value(IdKey));
|
||||
d->osType = osTypeFromString(map.value(ClientOsTypeKey, osTypeToString(OsTypeLinux)).toString());
|
||||
d->osType = osTypeFromString(map.value(ClientOsTypeKey).toString()).value_or(OsTypeLinux);
|
||||
if (!d->id.isValid())
|
||||
d->id = newId();
|
||||
d->origin = static_cast<Origin>(map.value(OriginKey, ManuallyAdded).toInt());
|
||||
|
Reference in New Issue
Block a user