forked from qt-creator/qt-creator
Docker: Add Filepath::localSource()
FilePath::localSource can return a filepath that represents a local version of a remote file. It is used to let the debugger select the local version of a file when debugging a remote target. Change-Id: Ieb934ef0d454e8ff55e71df41dca825974d85da7 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -1588,6 +1588,16 @@ FilePath FilePath::resolvePath(const QString &tail) const
|
||||
return resolvePath(FilePath::fromString(tail));
|
||||
}
|
||||
|
||||
expected_str<FilePath> FilePath::localSource() const
|
||||
{
|
||||
if (!needsDevice())
|
||||
return *this;
|
||||
|
||||
QTC_ASSERT(s_deviceHooks.localSource,
|
||||
return make_unexpected(Tr::tr("No 'localSource' device hook set.")));
|
||||
return s_deviceHooks.localSource(*this);
|
||||
}
|
||||
|
||||
// Cleans path part similar to QDir::cleanPath()
|
||||
// - directory separators normalized (that is, platform-native
|
||||
// separators converted to "/") and redundant ones removed, and "."s and ".."s
|
||||
|
@@ -238,6 +238,8 @@ public:
|
||||
[[nodiscard]] static int schemeAndHostLength(const QStringView path);
|
||||
|
||||
static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);
|
||||
//! Returns a filepath the represents the same file on a local drive
|
||||
expected_str<FilePath> localSource() const;
|
||||
|
||||
private:
|
||||
friend class ::tst_fileutils;
|
||||
@@ -268,6 +270,7 @@ public:
|
||||
std::function<bool(const FilePath &, const FilePath &)> ensureReachable;
|
||||
std::function<Environment(const FilePath &)> environment;
|
||||
std::function<bool(const FilePath &left, const FilePath &right)> isSameDevice;
|
||||
std::function<expected_str<FilePath>(const FilePath &)> localSource;
|
||||
};
|
||||
|
||||
} // namespace Utils
|
||||
|
@@ -1165,7 +1165,9 @@ void GdbEngine::handleStopResponse(const GdbMi &data)
|
||||
showMessage("INVALID STOPPED REASON", LogWarning);
|
||||
}
|
||||
|
||||
const FilePath fileName = FilePath::fromString(fullName);
|
||||
const FilePath onDevicePath = FilePath::fromString(fullName).onDevice(
|
||||
runParameters().debugger.command.executable());
|
||||
const FilePath fileName = onDevicePath.localSource().value_or(onDevicePath);
|
||||
|
||||
if (!nr.isEmpty() && frame.isValid()) {
|
||||
// Use opportunity to update the breakpoint marker position.
|
||||
|
@@ -74,7 +74,8 @@ StackFrame StackFrame::parseFrame(const GdbMi &frameMi, const DebuggerRunParamet
|
||||
frame.function = frameMi["function"].data();
|
||||
frame.module = frameMi["module"].data();
|
||||
const FilePath debugger = rp.debugger.command.executable();
|
||||
frame.file = FilePath::fromString(frameMi["file"].data()).onDevice(debugger);
|
||||
const FilePath onDevicePath = FilePath::fromString(frameMi["file"].data()).onDevice(debugger);
|
||||
frame.file = onDevicePath.localSource().value_or(onDevicePath);
|
||||
frame.line = frameMi["line"].toInt();
|
||||
frame.address = frameMi["address"].toAddress();
|
||||
frame.context = frameMi["context"].data();
|
||||
|
@@ -144,6 +144,7 @@ public:
|
||||
void changeMounts(QStringList newMounts);
|
||||
bool ensureReachable(const FilePath &other);
|
||||
void shutdown();
|
||||
expected_str<FilePath> localSource(const FilePath &other) const;
|
||||
|
||||
QString containerId() { return m_container; }
|
||||
DockerDeviceData data() { return m_data; }
|
||||
@@ -828,6 +829,11 @@ bool DockerDevice::ensureReachable(const FilePath &other) const
|
||||
return d->ensureReachable(other.parentDir());
|
||||
}
|
||||
|
||||
expected_str<FilePath> DockerDevice::localSource(const Utils::FilePath &other) const
|
||||
{
|
||||
return d->localSource(other);
|
||||
}
|
||||
|
||||
Environment DockerDevice::systemEnvironment() const
|
||||
{
|
||||
return d->environment();
|
||||
@@ -1125,6 +1131,27 @@ void DockerDevicePrivate::changeMounts(QStringList newMounts)
|
||||
}
|
||||
}
|
||||
|
||||
expected_str<FilePath> DockerDevicePrivate::localSource(const FilePath &other) const
|
||||
{
|
||||
const auto devicePath = FilePath::fromString(other.path());
|
||||
for (const TemporaryMountInfo &info : m_temporaryMounts) {
|
||||
if (devicePath.isChildOf(info.containerPath)) {
|
||||
const FilePath relativePath = devicePath.relativeChildPath(info.containerPath);
|
||||
return info.path.pathAppended(relativePath.path());
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &mount : m_data.mounts) {
|
||||
const FilePath mountPoint = FilePath::fromString(mount);
|
||||
if (devicePath.isChildOf(mountPoint)) {
|
||||
const FilePath relativePath = devicePath.relativeChildPath(mountPoint);
|
||||
return mountPoint.pathAppended(relativePath.path());
|
||||
}
|
||||
}
|
||||
|
||||
return make_unexpected(Tr::tr("localSource: No mount point found for %1").arg(other.toString()));
|
||||
}
|
||||
|
||||
bool DockerDevicePrivate::ensureReachable(const FilePath &other)
|
||||
{
|
||||
for (const QString &mount : m_data.mounts) {
|
||||
|
@@ -86,6 +86,7 @@ public:
|
||||
|
||||
bool handlesFile(const Utils::FilePath &filePath) const override;
|
||||
bool ensureReachable(const Utils::FilePath &other) const override;
|
||||
Utils::expected_str<Utils::FilePath> localSource(const Utils::FilePath &other) const override;
|
||||
|
||||
Utils::Environment systemEnvironment() const override;
|
||||
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "devicemanager.h"
|
||||
|
||||
#include "idevicefactory.h"
|
||||
#include "projectexplorertr.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
@@ -414,6 +415,13 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
|
||||
return leftDevice == rightDevice;
|
||||
};
|
||||
|
||||
deviceHooks.localSource = [](const FilePath &file) -> expected_str<FilePath> {
|
||||
auto device = DeviceManager::deviceForPath(file);
|
||||
if (!device)
|
||||
return make_unexpected(Tr::tr("No device for path \"%1\"").arg(file.toUserOutput()));
|
||||
return device->localSource(file);
|
||||
};
|
||||
|
||||
deviceHooks.fileAccess = [](const FilePath &filePath) -> DeviceFileAccess * {
|
||||
if (!filePath.needsDevice())
|
||||
return DesktopDeviceFileAccess::instance();
|
||||
|
@@ -10,11 +10,11 @@
|
||||
|
||||
#include "../kit.h"
|
||||
#include "../kitinformation.h"
|
||||
#include "../projectexplorertr.h"
|
||||
#include "../target.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <utils/devicefileaccess.h>
|
||||
#include <utils/displayname.h>
|
||||
#include <utils/icon.h>
|
||||
@@ -630,6 +630,12 @@ bool IDevice::ensureReachable(const FilePath &other) const
|
||||
return handlesFile(other); // Some first approximation.
|
||||
}
|
||||
|
||||
expected_str<FilePath> IDevice::localSource(const Utils::FilePath &other) const
|
||||
{
|
||||
Q_UNUSED(other);
|
||||
return make_unexpected(Tr::tr("localSource() not implemented for this device type."));
|
||||
}
|
||||
|
||||
bool IDevice::prepareForBuild(const Target *target)
|
||||
{
|
||||
Q_UNUSED(target)
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "idevicefwd.h"
|
||||
|
||||
#include <utils/id.h>
|
||||
#include <utils/expected.h>
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/tasktree.h>
|
||||
@@ -215,6 +216,7 @@ public:
|
||||
virtual void aboutToBeRemoved() const {}
|
||||
|
||||
virtual bool ensureReachable(const Utils::FilePath &other) const;
|
||||
virtual Utils::expected_str<Utils::FilePath> localSource(const Utils::FilePath &other) const;
|
||||
|
||||
virtual bool prepareForBuild(const Target *target);
|
||||
virtual std::optional<Utils::FilePath> clangdExecutable() const;
|
||||
|
Reference in New Issue
Block a user