forked from qt-creator/qt-creator
Utils: Split off file access interface from IDevice
The file accessing functions form now a class hierarchy by themselves, the devices return a suitable point. The previous implementation was mildly confusing by the special handling of the DesktopDevice, fallbacks and remote cases in the same function leading to unnecessary boilerplate when adding new functions and codepaths that sometimes passed the FilePath API twice. Implemented are a "DesktopDeviceFileAccess" taking care of the previous !needsDevice() branches and a "UnixDeviceFileAccess" covering the current docker and RL uses. As a side-effect this unifies to a large degree the current docker and RL code paths with were occasionally deviating from each other while they shouldn't. Change-Id: I4ff59d4be2a07d13e2ca5e9ace26a84160a87c9d Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
@@ -28,6 +28,7 @@ add_qtc_library(Utils
|
|||||||
delegates.cpp delegates.h
|
delegates.cpp delegates.h
|
||||||
detailsbutton.cpp detailsbutton.h
|
detailsbutton.cpp detailsbutton.h
|
||||||
detailswidget.cpp detailswidget.h
|
detailswidget.cpp detailswidget.h
|
||||||
|
devicefileaccess.cpp devicefileaccess.h
|
||||||
deviceshell.cpp deviceshell.h
|
deviceshell.cpp deviceshell.h
|
||||||
differ.cpp differ.h
|
differ.cpp differ.h
|
||||||
displayname.cpp displayname.h
|
displayname.cpp displayname.h
|
||||||
|
|||||||
862
src/libs/utils/devicefileaccess.cpp
Normal file
862
src/libs/utils/devicefileaccess.cpp
Normal file
@@ -0,0 +1,862 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "devicefileaccess.h"
|
||||||
|
|
||||||
|
#include "algorithm.h"
|
||||||
|
#include "qtcassert.h"
|
||||||
|
#include "hostosinfo.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QStorageInfo>
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
|
||||||
|
// DeviceFileAccess
|
||||||
|
|
||||||
|
DeviceFileAccess::~DeviceFileAccess() = default;
|
||||||
|
|
||||||
|
QString DeviceFileAccess::mapToDevicePath(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return filePath.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::isExecutableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::isReadableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::isWritableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::isReadableDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::isWritableDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::isFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::isDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
if (isWritableDirectory(filePath))
|
||||||
|
return true;
|
||||||
|
return createDirectory(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::ensureExistingFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::createDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::exists(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::removeFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
Q_UNUSED(error)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
Q_UNUSED(target)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
Q_UNUSED(target)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OsType DeviceFileAccess::osType(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
return OsTypeOther;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath DeviceFileAccess::symLinkTarget(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceFileAccess::iterateDirectory(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const FilePath::IterateDirCallback &callBack,
|
||||||
|
const FileFilter &filter) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
Q_UNUSED(callBack)
|
||||||
|
Q_UNUSED(filter)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<QByteArray> DeviceFileAccess::fileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
Q_UNUSED(limit)
|
||||||
|
Q_UNUSED(offset)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::writeFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
Q_UNUSED(data)
|
||||||
|
Q_UNUSED(offset)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePathInfo DeviceFileAccess::filePathInfo(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime DeviceFileAccess::lastModified(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile::Permissions DeviceFileAccess::permissions(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 DeviceFileAccess::fileSize(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 DeviceFileAccess::bytesAvailable(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceFileAccess::asyncFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const Continuation<std::optional<QByteArray>> &cont,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
cont(fileContents(filePath, limit, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceFileAccess::asyncWriteFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const Continuation<bool> &cont,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
cont(writeFileContents(filePath, data, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceFileAccess::asyncCopyFile(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const Continuation<bool> &cont,
|
||||||
|
const FilePath &target) const
|
||||||
|
{
|
||||||
|
cont(copyFile(filePath, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DesktopDeviceFileAccess
|
||||||
|
|
||||||
|
DesktopDeviceFileAccess::~DesktopDeviceFileAccess() = default;
|
||||||
|
|
||||||
|
DesktopDeviceFileAccess *DesktopDeviceFileAccess::instance()
|
||||||
|
{
|
||||||
|
static DesktopDeviceFileAccess theInstance;
|
||||||
|
return &theInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::isExecutableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath.path());
|
||||||
|
return fi.isExecutable() && !fi.isDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::isReadableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath.path());
|
||||||
|
return fi.exists() && fi.isFile() && fi.isReadable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::isWritableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath.path());
|
||||||
|
return fi.exists() && fi.isFile() && fi.isWritable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::isReadableDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath.path());
|
||||||
|
return fi.exists() && fi.isDir() && fi.isReadable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::isWritableDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath.path());
|
||||||
|
return fi.exists() && fi.isDir() && fi.isWritable();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::isFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath.path());
|
||||||
|
return fi.isFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::isDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath.path());
|
||||||
|
return fi.isDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath.path());
|
||||||
|
if (fi.isDir() && fi.isWritable())
|
||||||
|
return true;
|
||||||
|
return QDir().mkpath(filePath.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
QFile f(filePath.path());
|
||||||
|
if (f.exists())
|
||||||
|
return true;
|
||||||
|
f.open(QFile::WriteOnly);
|
||||||
|
f.close();
|
||||||
|
return f.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::createDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
QDir dir(filePath.path());
|
||||||
|
return dir.mkpath(dir.absolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::exists(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return !filePath.isEmpty() && QFileInfo::exists(filePath.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::removeFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return QFile::remove(filePath.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!filePath.needsDevice(), return false);
|
||||||
|
QFileInfo fileInfo = filePath.toFileInfo();
|
||||||
|
if (!fileInfo.exists() && !fileInfo.isSymLink())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
QFile::setPermissions(fileInfo.absoluteFilePath(), fileInfo.permissions() | QFile::WriteUser);
|
||||||
|
|
||||||
|
if (fileInfo.isDir()) {
|
||||||
|
QDir dir(fileInfo.absoluteFilePath());
|
||||||
|
dir.setPath(dir.canonicalPath());
|
||||||
|
if (dir.isRoot()) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("Utils::FileUtils",
|
||||||
|
"Refusing to remove root directory.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dir.path() == QDir::home().canonicalPath()) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("Utils::FileUtils",
|
||||||
|
"Refusing to remove your home directory.");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QStringList fileNames = dir.entryList(
|
||||||
|
QDir::Files | QDir::Hidden | QDir::System | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for (const QString &fileName : fileNames) {
|
||||||
|
if (!removeRecursively(filePath / fileName, error))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!QDir::root().rmdir(dir.path())) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to remove directory \"%1\".")
|
||||||
|
.arg(filePath.toUserOutput());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!QFile::remove(filePath.toString())) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to remove file \"%1\".")
|
||||||
|
.arg(filePath.toUserOutput());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const
|
||||||
|
{
|
||||||
|
return QFile::copy(filePath.path(), target.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
||||||
|
{
|
||||||
|
return QFile::rename(filePath.path(), target.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePathInfo DesktopDeviceFileAccess::filePathInfo(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
FilePathInfo result;
|
||||||
|
|
||||||
|
QFileInfo fi(filePath.path());
|
||||||
|
result.fileSize = fi.size();
|
||||||
|
result.lastModified = fi.lastModified();
|
||||||
|
result.fileFlags = (FilePathInfo::FileFlag) int(fi.permissions());
|
||||||
|
|
||||||
|
if (fi.isDir())
|
||||||
|
result.fileFlags |= FilePathInfo::DirectoryType;
|
||||||
|
if (fi.isFile())
|
||||||
|
result.fileFlags |= FilePathInfo::FileType;
|
||||||
|
if (fi.exists())
|
||||||
|
result.fileFlags |= FilePathInfo::ExistsFlag;
|
||||||
|
if (fi.isSymbolicLink())
|
||||||
|
result.fileFlags |= FilePathInfo::LinkType;
|
||||||
|
if (fi.isBundle())
|
||||||
|
result.fileFlags |= FilePathInfo::BundleType;
|
||||||
|
if (fi.isHidden())
|
||||||
|
result.fileFlags |= FilePathInfo::HiddenFlag;
|
||||||
|
if (fi.isRoot())
|
||||||
|
result.fileFlags |= FilePathInfo::RootFlag;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath DesktopDeviceFileAccess::symLinkTarget(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QFileInfo info(filePath.path());
|
||||||
|
if (!info.isSymLink())
|
||||||
|
return {};
|
||||||
|
return FilePath::fromString(info.symLinkTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DesktopDeviceFileAccess::iterateDirectory(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const FilePath::IterateDirCallback &callBack,
|
||||||
|
const FileFilter &filter) const
|
||||||
|
{
|
||||||
|
QDirIterator it(filePath.path(), filter.nameFilters, filter.fileFilters, filter.iteratorFlags);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
const FilePath path = FilePath::fromString(it.next());
|
||||||
|
bool res = false;
|
||||||
|
if (callBack.index() == 0)
|
||||||
|
res = std::get<0>(callBack)(path);
|
||||||
|
else
|
||||||
|
res = std::get<1>(callBack)(path, path.filePathInfo());
|
||||||
|
if (!res)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<QByteArray> DesktopDeviceFileAccess::fileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
QFile f(path);
|
||||||
|
if (!f.exists())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!f.open(QFile::ReadOnly))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (offset != 0)
|
||||||
|
f.seek(offset);
|
||||||
|
|
||||||
|
if (limit != -1)
|
||||||
|
return f.read(limit);
|
||||||
|
|
||||||
|
return f.readAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::writeFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
QFile file(filePath.path());
|
||||||
|
QTC_ASSERT(file.open(QFile::WriteOnly | QFile::Truncate), return false);
|
||||||
|
if (offset != 0)
|
||||||
|
file.seek(offset);
|
||||||
|
qint64 res = file.write(data);
|
||||||
|
return res == data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime DesktopDeviceFileAccess::lastModified(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return QFileInfo(filePath.path()).lastModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile::Permissions DesktopDeviceFileAccess::permissions(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return QFileInfo(filePath.path()).permissions();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DesktopDeviceFileAccess::setPermissions(const FilePath &filePath,
|
||||||
|
QFile::Permissions permissions) const
|
||||||
|
{
|
||||||
|
return QFile(filePath.path()).setPermissions(permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 DesktopDeviceFileAccess::fileSize(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return QFileInfo(filePath.path()).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 DesktopDeviceFileAccess::bytesAvailable(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return QStorageInfo(filePath.path()).bytesAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
OsType DesktopDeviceFileAccess::osType(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath);
|
||||||
|
return HostOsInfo::hostOs();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// UnixDeviceAccess
|
||||||
|
|
||||||
|
UnixDeviceFileAccess::~UnixDeviceFileAccess() = default;
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::runInShellSuccess(
|
||||||
|
const QString &executable,
|
||||||
|
const QStringList &args,
|
||||||
|
const QByteArray &stdInData) const
|
||||||
|
{
|
||||||
|
return runInShell(executable, args, stdInData).exitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::isExecutableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("test", {"-x", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::isReadableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("test", {"-r", path, "-a", "-f", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::isWritableFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("test", {"-w", path, "-a", "-f", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::isReadableDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("test", {"-r", path, "-a", "-d", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::isWritableDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("test", {"-w", path, "-a", "-d", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::isFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("test", {"-f", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("test", {"-d", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("touch", {path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::createDirectory(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("mkdir", {"-p", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::exists(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const QString path = filePath.path();
|
||||||
|
return runInShellSuccess("test", {"-e", path});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::removeFile(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return runInShellSuccess("rm", {filePath.path()});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(filePath.path().startsWith('/'), return false);
|
||||||
|
|
||||||
|
const QString path = filePath.cleanPath().path();
|
||||||
|
// We are expecting this only to be called in a context of build directories or similar.
|
||||||
|
// Chicken out in some cases that _might_ be user code errors.
|
||||||
|
QTC_ASSERT(path.startsWith('/'), return false);
|
||||||
|
int levelsNeeded = path.startsWith("/home/") ? 4 : 3;
|
||||||
|
if (path.startsWith("/tmp/"))
|
||||||
|
levelsNeeded = 2;
|
||||||
|
QTC_ASSERT(path.count('/') >= levelsNeeded, return false);
|
||||||
|
|
||||||
|
RunResult result = runInShell("rm", {"-rf", "--", path});
|
||||||
|
if (error)
|
||||||
|
*error = QString::fromUtf8(result.stdErr);
|
||||||
|
return result.exitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const
|
||||||
|
{
|
||||||
|
return runInShellSuccess("cp", {filePath.path(), target.path()});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const
|
||||||
|
{
|
||||||
|
return runInShellSuccess("mv", {filePath.path(), target.path()});
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath UnixDeviceFileAccess::symLinkTarget(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const RunResult result = runInShell("readlink", {"-n", "-e", filePath.path()});
|
||||||
|
const QString out = QString::fromUtf8(result.stdOut);
|
||||||
|
return out.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<QByteArray> UnixDeviceFileAccess::fileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
QStringList args = {"if=" + filePath.path(), "status=none"};
|
||||||
|
if (limit > 0 || offset > 0) {
|
||||||
|
const qint64 gcd = std::gcd(limit, offset);
|
||||||
|
args += QString("bs=%1").arg(gcd);
|
||||||
|
args += QString("count=%1").arg(limit / gcd);
|
||||||
|
args += QString("seek=%1").arg(offset / gcd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const RunResult r = runInShell("dd", args);
|
||||||
|
|
||||||
|
if (r.exitCode != 0)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return r.stdOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::writeFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
QStringList args = {"of=" + filePath.path()};
|
||||||
|
if (offset != 0) {
|
||||||
|
args.append("bs=1");
|
||||||
|
args.append(QString("seek=%1").arg(offset));
|
||||||
|
}
|
||||||
|
return runInShellSuccess("dd", args, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
OsType UnixDeviceFileAccess::osType(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
Q_UNUSED(filePath)
|
||||||
|
return OsTypeLinux;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const RunResult result = runInShell("stat", {"-L", "-c", "%Y", filePath.path()});
|
||||||
|
qint64 secs = result.stdOut.toLongLong();
|
||||||
|
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const RunResult result = runInShell("stat", {"-L", "-c", "%a", filePath.path()});
|
||||||
|
const uint bits = result.stdOut.toUInt(nullptr, 8);
|
||||||
|
QFileDevice::Permissions perm = {};
|
||||||
|
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
||||||
|
BIT(0, ExeOther);
|
||||||
|
BIT(1, WriteOther);
|
||||||
|
BIT(2, ReadOther);
|
||||||
|
BIT(3, ExeGroup);
|
||||||
|
BIT(4, WriteGroup);
|
||||||
|
BIT(5, ReadGroup);
|
||||||
|
BIT(6, ExeUser);
|
||||||
|
BIT(7, WriteUser);
|
||||||
|
BIT(8, ReadUser);
|
||||||
|
#undef BIT
|
||||||
|
return perm;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions perms) const
|
||||||
|
{
|
||||||
|
const int flags = int(perms);
|
||||||
|
return runInShellSuccess("chmod", {QString::number(flags, 16), filePath.path()});
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const RunResult result = runInShell("stat", {"-L", "-c", "%s", filePath.path()});
|
||||||
|
return result.stdOut.toLongLong();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 UnixDeviceFileAccess::bytesAvailable(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const RunResult result = runInShell("df", {"-k", filePath.path()});
|
||||||
|
return FileUtils::bytesAvailableFromDFOutput(result.stdOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const
|
||||||
|
{
|
||||||
|
const RunResult stat = runInShell("stat", {"-L", "-c", "%f %Y %s", filePath.path()});
|
||||||
|
return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut));
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns whether 'find' could be used.
|
||||||
|
bool UnixDeviceFileAccess::iterateWithFind(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const FileFilter &filter,
|
||||||
|
const FilePath::IterateDirCallback &callBack) const
|
||||||
|
{
|
||||||
|
QTC_CHECK(filePath.isAbsolutePath());
|
||||||
|
|
||||||
|
QStringList arguments = filter.asFindArguments(filePath.path());
|
||||||
|
|
||||||
|
// TODO: Using stat -L will always return the link target, not the link itself.
|
||||||
|
// We may wan't to add the information that it is a link at some point.
|
||||||
|
if (callBack.index() == 1)
|
||||||
|
arguments.append(R"(-exec echo -n \"{}\"" " \; -exec stat -L -c "%f %Y %s" "{}" \;)");
|
||||||
|
|
||||||
|
const RunResult result = runInShell("find", arguments);
|
||||||
|
const QString out = QString::fromUtf8(result.stdOut);
|
||||||
|
if (result.exitCode != 0) {
|
||||||
|
// Find returns non-zero exit code for any error it encounters, even if it finds some files.
|
||||||
|
|
||||||
|
if (!out.startsWith('"' + filePath.path())) {
|
||||||
|
if (!filePath.exists()) // File does not exist, so no files to find.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If the output does not start with the path we are searching in, find has failed.
|
||||||
|
// Possibly due to unknown options.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList entries = out.split("\n", Qt::SkipEmptyParts);
|
||||||
|
if (entries.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const auto toFilePath = [&filePath, &callBack](const QString &entry) -> bool {
|
||||||
|
if (callBack.index() == 0)
|
||||||
|
return std::get<0>(callBack)(filePath.withNewPath(entry));
|
||||||
|
|
||||||
|
const QString fileName = entry.mid(1, entry.lastIndexOf('\"') - 1);
|
||||||
|
const QString infos = entry.mid(fileName.length() + 3);
|
||||||
|
|
||||||
|
const FilePathInfo fi = FileUtils::filePathInfoFromTriple(infos);
|
||||||
|
if (!fi.fileFlags)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const FilePath fp = filePath.withNewPath(fileName);
|
||||||
|
return std::get<1>(callBack)(fp, fi);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove the first line, this can be the directory we are searching in.
|
||||||
|
// as long as we do not specify "mindepth > 0"
|
||||||
|
if (entries.front() == filePath.path())
|
||||||
|
entries.pop_front();
|
||||||
|
|
||||||
|
for (const QString &entry : entries) {
|
||||||
|
if (!toFilePath(entry))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnixDeviceFileAccess::findUsingLs(
|
||||||
|
const QString ¤t,
|
||||||
|
const FileFilter &filter,
|
||||||
|
QStringList *found) const
|
||||||
|
{
|
||||||
|
const RunResult result = runInShell("ls", {"-1", "-p", "--", current});
|
||||||
|
const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts);
|
||||||
|
for (QString entry : entries) {
|
||||||
|
const QChar last = entry.back();
|
||||||
|
if (last == '/') {
|
||||||
|
entry.chop(1);
|
||||||
|
if (filter.iteratorFlags.testFlag(QDirIterator::Subdirectories))
|
||||||
|
findUsingLs(current + '/' + entry, filter, found);
|
||||||
|
}
|
||||||
|
found->append(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used on 'ls' output on unix-like systems.
|
||||||
|
static void iterateLsOutput(const FilePath &base,
|
||||||
|
const QStringList &entries,
|
||||||
|
const FileFilter &filter,
|
||||||
|
const FilePath::IterateDirCallback &callBack)
|
||||||
|
{
|
||||||
|
const QList<QRegularExpression> nameRegexps =
|
||||||
|
transform(filter.nameFilters, [](const QString &filter) {
|
||||||
|
QRegularExpression re;
|
||||||
|
re.setPattern(QRegularExpression::wildcardToRegularExpression(filter));
|
||||||
|
QTC_CHECK(re.isValid());
|
||||||
|
return re;
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto nameMatches = [&nameRegexps](const QString &fileName) {
|
||||||
|
for (const QRegularExpression &re : nameRegexps) {
|
||||||
|
const QRegularExpressionMatch match = re.match(fileName);
|
||||||
|
if (match.hasMatch())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return nameRegexps.isEmpty();
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: Handle filters. For now bark on unsupported options.
|
||||||
|
QTC_CHECK(filter.fileFilters == QDir::NoFilter);
|
||||||
|
|
||||||
|
for (const QString &entry : entries) {
|
||||||
|
if (!nameMatches(entry))
|
||||||
|
continue;
|
||||||
|
const FilePath current = base.pathAppended(entry);
|
||||||
|
bool res = false;
|
||||||
|
if (callBack.index() == 0)
|
||||||
|
res = std::get<0>(callBack)(current);
|
||||||
|
else
|
||||||
|
res = std::get<1>(callBack)(current, current.filePathInfo());
|
||||||
|
if (!res)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnixDeviceFileAccess::iterateDirectory(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const FilePath::IterateDirCallback &callBack,
|
||||||
|
const FileFilter &filter) const
|
||||||
|
{
|
||||||
|
// We try to use 'find' first, because that can filter better directly.
|
||||||
|
// Unfortunately, it's not installed on all devices by default.
|
||||||
|
if (m_tryUseFind) {
|
||||||
|
if (iterateWithFind(filePath, filter, callBack))
|
||||||
|
return;
|
||||||
|
m_tryUseFind = false; // remember the failure for the next time and use the 'ls' fallback below.
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we do not have find - use ls as fallback
|
||||||
|
QStringList entries;
|
||||||
|
findUsingLs(filePath.path(), filter, &entries);
|
||||||
|
iterateLsOutput(filePath, entries, filter, callBack);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Utils
|
||||||
194
src/libs/utils/devicefileaccess.h
Normal file
194
src/libs/utils/devicefileaccess.h
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
// Copyright (C) 2022 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils_global.h"
|
||||||
|
|
||||||
|
#include "fileutils.h"
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
|
||||||
|
// Base class including dummy implementation usable as fallback.
|
||||||
|
class QTCREATOR_UTILS_EXPORT DeviceFileAccess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~DeviceFileAccess();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class FilePath;
|
||||||
|
|
||||||
|
virtual QString mapToDevicePath(const FilePath &filePath) const;
|
||||||
|
|
||||||
|
virtual bool isExecutableFile(const FilePath &filePath) const;
|
||||||
|
virtual bool isReadableFile(const FilePath &filePath) const;
|
||||||
|
virtual bool isWritableFile(const FilePath &filePath) const;
|
||||||
|
virtual bool isReadableDirectory(const FilePath &filePath) const;
|
||||||
|
virtual bool isWritableDirectory(const FilePath &filePath) const;
|
||||||
|
virtual bool isFile(const FilePath &filePath) const;
|
||||||
|
virtual bool isDirectory(const FilePath &filePath) const;
|
||||||
|
virtual bool ensureWritableDirectory(const FilePath &filePath) const;
|
||||||
|
virtual bool ensureExistingFile(const FilePath &filePath) const;
|
||||||
|
virtual bool createDirectory(const FilePath &filePath) const;
|
||||||
|
virtual bool exists(const FilePath &filePath) const;
|
||||||
|
virtual bool removeFile(const FilePath &filePath) const;
|
||||||
|
virtual bool removeRecursively(const FilePath &filePath, QString *error) const;
|
||||||
|
virtual bool copyFile(const FilePath &filePath, const FilePath &target) const;
|
||||||
|
virtual bool renameFile(const FilePath &filePath, const FilePath &target) const;
|
||||||
|
|
||||||
|
virtual OsType osType(const FilePath &filePath) const;
|
||||||
|
virtual FilePath symLinkTarget(const FilePath &filePath) const;
|
||||||
|
virtual FilePathInfo filePathInfo(const FilePath &filePath) const;
|
||||||
|
virtual QDateTime lastModified(const FilePath &filePath) const;
|
||||||
|
virtual QFile::Permissions permissions(const FilePath &filePath) const;
|
||||||
|
virtual bool setPermissions(const FilePath &filePath, QFile::Permissions) const;
|
||||||
|
virtual qint64 fileSize(const FilePath &filePath) const;
|
||||||
|
virtual qint64 bytesAvailable(const FilePath &filePath) const;
|
||||||
|
|
||||||
|
virtual void iterateDirectory(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const FilePath::IterateDirCallback &callBack,
|
||||||
|
const FileFilter &filter) const;
|
||||||
|
|
||||||
|
virtual std::optional<QByteArray> fileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const;
|
||||||
|
virtual bool writeFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const;
|
||||||
|
|
||||||
|
virtual void asyncFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const Continuation<std::optional<QByteArray>> &cont,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const;
|
||||||
|
|
||||||
|
virtual void asyncWriteFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const Continuation<bool> &cont,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const;
|
||||||
|
|
||||||
|
virtual void asyncCopyFile(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const Continuation<bool> &cont,
|
||||||
|
const FilePath &target) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QTCREATOR_UTILS_EXPORT DesktopDeviceFileAccess : public DeviceFileAccess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~DesktopDeviceFileAccess() override;
|
||||||
|
|
||||||
|
static DesktopDeviceFileAccess *instance();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool isExecutableFile(const FilePath &filePath) const override;
|
||||||
|
bool isReadableFile(const FilePath &filePath) const override;
|
||||||
|
bool isWritableFile(const FilePath &filePath) const override;
|
||||||
|
bool isReadableDirectory(const FilePath &filePath) const override;
|
||||||
|
bool isWritableDirectory(const FilePath &filePath) const override;
|
||||||
|
bool isFile(const FilePath &filePath) const override;
|
||||||
|
bool isDirectory(const FilePath &filePath) const override;
|
||||||
|
bool ensureWritableDirectory(const FilePath &filePath) const override;
|
||||||
|
bool ensureExistingFile(const FilePath &filePath) const override;
|
||||||
|
bool createDirectory(const FilePath &filePath) const override;
|
||||||
|
bool exists(const FilePath &filePath) const override;
|
||||||
|
bool removeFile(const FilePath &filePath) const override;
|
||||||
|
bool removeRecursively(const FilePath &filePath, QString *error) const override;
|
||||||
|
bool copyFile(const FilePath &filePath, const FilePath &target) const override;
|
||||||
|
bool renameFile(const FilePath &filePath, const FilePath &target) const override;
|
||||||
|
|
||||||
|
OsType osType(const FilePath &filePath) const override;
|
||||||
|
FilePath symLinkTarget(const FilePath &filePath) const override;
|
||||||
|
FilePathInfo filePathInfo(const FilePath &filePath) const override;
|
||||||
|
QDateTime lastModified(const FilePath &filePath) const override;
|
||||||
|
QFile::Permissions permissions(const FilePath &filePath) const override;
|
||||||
|
bool setPermissions(const FilePath &filePath, QFile::Permissions) const override;
|
||||||
|
qint64 fileSize(const FilePath &filePath) const override;
|
||||||
|
qint64 bytesAvailable(const FilePath &filePath) const override;
|
||||||
|
|
||||||
|
void iterateDirectory(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const FilePath::IterateDirCallback &callBack,
|
||||||
|
const FileFilter &filter) const override;
|
||||||
|
|
||||||
|
std::optional<QByteArray> fileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const override;
|
||||||
|
bool writeFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QTCREATOR_UTILS_EXPORT UnixDeviceFileAccess : public DeviceFileAccess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~UnixDeviceFileAccess() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual RunResult runInShell(
|
||||||
|
const QString &executable,
|
||||||
|
const QStringList &args,
|
||||||
|
const QByteArray &inputData = {}) const = 0;
|
||||||
|
bool runInShellSuccess(
|
||||||
|
const QString &executable,
|
||||||
|
const QStringList &args,
|
||||||
|
const QByteArray &stdInData = {}) const;
|
||||||
|
|
||||||
|
bool isExecutableFile(const FilePath &filePath) const override;
|
||||||
|
bool isReadableFile(const FilePath &filePath) const override;
|
||||||
|
bool isWritableFile(const FilePath &filePath) const override;
|
||||||
|
bool isReadableDirectory(const FilePath &filePath) const override;
|
||||||
|
bool isWritableDirectory(const FilePath &filePath) const override;
|
||||||
|
bool isFile(const FilePath &filePath) const override;
|
||||||
|
bool isDirectory(const FilePath &filePath) const override;
|
||||||
|
bool ensureExistingFile(const FilePath &filePath) const override;
|
||||||
|
bool createDirectory(const FilePath &filePath) const override;
|
||||||
|
bool exists(const FilePath &filePath) const override;
|
||||||
|
bool removeFile(const FilePath &filePath) const override;
|
||||||
|
bool removeRecursively(const FilePath &filePath, QString *error) const override;
|
||||||
|
bool copyFile(const FilePath &filePath, const FilePath &target) const override;
|
||||||
|
bool renameFile(const FilePath &filePath, const FilePath &target) const override;
|
||||||
|
|
||||||
|
FilePathInfo filePathInfo(const FilePath &filePath) const override;
|
||||||
|
OsType osType(const FilePath &filePath) const override;
|
||||||
|
FilePath symLinkTarget(const FilePath &filePath) const override;
|
||||||
|
QDateTime lastModified(const FilePath &filePath) const override;
|
||||||
|
QFile::Permissions permissions(const FilePath &filePath) const override;
|
||||||
|
bool setPermissions(const FilePath &filePath, QFile::Permissions) const override;
|
||||||
|
qint64 fileSize(const FilePath &filePath) const override;
|
||||||
|
qint64 bytesAvailable(const FilePath &filePath) const override;
|
||||||
|
|
||||||
|
void iterateDirectory(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const FilePath::IterateDirCallback &callBack,
|
||||||
|
const FileFilter &filter) const override;
|
||||||
|
|
||||||
|
std::optional<QByteArray> fileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const override;
|
||||||
|
bool writeFileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const QByteArray &data,
|
||||||
|
qint64 offset) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool iterateWithFind(
|
||||||
|
const FilePath &filePath,
|
||||||
|
const FileFilter &filter,
|
||||||
|
const FilePath::IterateDirCallback &callBack) const;
|
||||||
|
void findUsingLs(
|
||||||
|
const QString ¤t,
|
||||||
|
const FileFilter &filter,
|
||||||
|
QStringList *found) const;
|
||||||
|
|
||||||
|
mutable bool m_tryUseFind = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Utils
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "filepath.h"
|
#include "filepath.h"
|
||||||
|
|
||||||
#include "algorithm.h"
|
#include "algorithm.h"
|
||||||
|
#include "devicefileaccess.h"
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
#include "hostosinfo.h"
|
#include "hostosinfo.h"
|
||||||
@@ -15,7 +16,6 @@
|
|||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QStorageInfo>
|
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QStringView>
|
#include <QStringView>
|
||||||
|
|
||||||
@@ -30,7 +30,6 @@
|
|||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
static DeviceFileHooks s_deviceHooks;
|
static DeviceFileHooks s_deviceHooks;
|
||||||
static bool removeRecursivelyLocal(const FilePath &filePath, QString *error);
|
|
||||||
inline bool isWindowsDriveLetter(QChar ch);
|
inline bool isWindowsDriveLetter(QChar ch);
|
||||||
|
|
||||||
|
|
||||||
@@ -359,136 +358,68 @@ void FilePath::setParts(const QStringView scheme, const QStringView host, const
|
|||||||
/// FilePath exists.
|
/// FilePath exists.
|
||||||
bool FilePath::exists() const
|
bool FilePath::exists() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->exists(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.exists, return false);
|
|
||||||
return s_deviceHooks.exists(*this);
|
|
||||||
}
|
|
||||||
return !isEmpty() && QFileInfo::exists(path());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns a bool indicating whether a path is writable.
|
/// \returns a bool indicating whether a path is writable.
|
||||||
bool FilePath::isWritableDir() const
|
bool FilePath::isWritableDir() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->isWritableDirectory(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.isWritableDir, return false);
|
|
||||||
return s_deviceHooks.isWritableDir(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo fi{path()};
|
|
||||||
return exists() && fi.isDir() && fi.isWritable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::isWritableFile() const
|
bool FilePath::isWritableFile() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->isWritableFile(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.isWritableFile, return false);
|
|
||||||
return s_deviceHooks.isWritableFile(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo fi{path()};
|
|
||||||
return fi.isWritable() && !fi.isDir();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::ensureWritableDir() const
|
bool FilePath::ensureWritableDir() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->ensureWritableDirectory(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.ensureWritableDir, return false);
|
|
||||||
return s_deviceHooks.ensureWritableDir(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo fi{path()};
|
|
||||||
if (fi.isDir() && fi.isWritable())
|
|
||||||
return true;
|
|
||||||
return QDir().mkpath(path());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::ensureExistingFile() const
|
bool FilePath::ensureExistingFile() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->ensureExistingFile(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.ensureExistingFile, return false);
|
|
||||||
return s_deviceHooks.ensureExistingFile(*this);
|
|
||||||
}
|
|
||||||
QFile f(path());
|
|
||||||
if (f.exists())
|
|
||||||
return true;
|
|
||||||
f.open(QFile::WriteOnly);
|
|
||||||
f.close();
|
|
||||||
return f.exists();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::isExecutableFile() const
|
bool FilePath::isExecutableFile() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->isExecutableFile(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.isExecutableFile, return false);
|
|
||||||
return s_deviceHooks.isExecutableFile(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo fi{path()};
|
|
||||||
return fi.isExecutable() && !fi.isDir();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::isReadableFile() const
|
bool FilePath::isReadableFile() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->isReadableFile(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.isReadableFile, return false);
|
|
||||||
return s_deviceHooks.isReadableFile(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo fi{path()};
|
|
||||||
return fi.isReadable() && !fi.isDir();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::isReadableDir() const
|
bool FilePath::isReadableDir() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->isReadableDirectory(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.isReadableDir, return false);
|
|
||||||
return s_deviceHooks.isReadableDir(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo fi{path()};
|
|
||||||
return fi.isReadable() && fi.isDir();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::isFile() const
|
bool FilePath::isFile() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->isFile(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.isFile, return false);
|
|
||||||
return s_deviceHooks.isFile(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo fi{path()};
|
|
||||||
return fi.isFile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::isDir() const
|
bool FilePath::isDir() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->isDirectory(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.isDir, return false);
|
|
||||||
return s_deviceHooks.isDir(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo fi{path()};
|
|
||||||
return fi.isDir();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::createDir() const
|
bool FilePath::createDir() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->createDirectory(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.createDir, return false);
|
|
||||||
return s_deviceHooks.createDir(*this);
|
|
||||||
}
|
|
||||||
QDir dir(path());
|
|
||||||
return dir.mkpath(dir.absolutePath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePaths FilePath::dirEntries(const FileFilter &filter, QDir::SortFlags sort) const
|
FilePaths FilePath::dirEntries(const FileFilter &filter, QDir::SortFlags sort) const
|
||||||
{
|
{
|
||||||
FilePaths result;
|
FilePaths result;
|
||||||
|
|
||||||
if (needsDevice()) {
|
const auto callBack = [&result](const FilePath &path) { result.append(path); return true; };
|
||||||
QTC_ASSERT(s_deviceHooks.iterateDirectory, return {});
|
iterateDirectory(callBack, filter);
|
||||||
const auto callBack = [&result](const FilePath &path) { result.append(path); return true; };
|
|
||||||
s_deviceHooks.iterateDirectory(*this, callBack, filter);
|
|
||||||
} else {
|
|
||||||
QDirIterator dit(path(), filter.nameFilters, filter.fileFilters, filter.iteratorFlags);
|
|
||||||
while (dit.hasNext())
|
|
||||||
result.append(FilePath::fromString(dit.next()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Not all flags supported here.
|
// FIXME: Not all flags supported here.
|
||||||
|
|
||||||
const QDir::SortFlags sortBy = (sort & QDir::SortByMask);
|
const QDir::SortFlags sortBy = (sort & QDir::SortByMask);
|
||||||
if (sortBy == QDir::Name) {
|
if (sortBy == QDir::Name) {
|
||||||
Utils::sort(result);
|
Utils::sort(result);
|
||||||
@@ -515,23 +446,7 @@ FilePaths FilePath::dirEntries(QDir::Filters filters) const
|
|||||||
|
|
||||||
void FilePath::iterateDirectory(const IterateDirCallback &callBack, const FileFilter &filter) const
|
void FilePath::iterateDirectory(const IterateDirCallback &callBack, const FileFilter &filter) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
fileAccess()->iterateDirectory(*this, callBack, filter);
|
||||||
QTC_ASSERT(s_deviceHooks.iterateDirectory, return);
|
|
||||||
s_deviceHooks.iterateDirectory(*this, callBack, filter);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDirIterator it(path(), filter.nameFilters, filter.fileFilters, filter.iteratorFlags);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
const FilePath path = FilePath::fromString(it.next());
|
|
||||||
bool res = false;
|
|
||||||
if (callBack.index() == 0)
|
|
||||||
res = std::get<0>(callBack)(path);
|
|
||||||
else
|
|
||||||
res = std::get<1>(callBack)(path, path.filePathInfo());
|
|
||||||
if (!res)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilePath::iterateDirectories(const FilePaths &dirs,
|
void FilePath::iterateDirectories(const FilePaths &dirs,
|
||||||
@@ -544,26 +459,7 @@ void FilePath::iterateDirectories(const FilePaths &dirs,
|
|||||||
|
|
||||||
std::optional<QByteArray> FilePath::fileContents(qint64 maxSize, qint64 offset) const
|
std::optional<QByteArray> FilePath::fileContents(qint64 maxSize, qint64 offset) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->fileContents(*this, maxSize, offset);
|
||||||
QTC_ASSERT(s_deviceHooks.fileContents, return {});
|
|
||||||
return s_deviceHooks.fileContents(*this, maxSize, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString path = toString();
|
|
||||||
QFile f(path);
|
|
||||||
if (!f.exists())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (!f.open(QFile::ReadOnly))
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (offset != 0)
|
|
||||||
f.seek(offset);
|
|
||||||
|
|
||||||
if (maxSize != -1)
|
|
||||||
return f.read(maxSize);
|
|
||||||
|
|
||||||
return f.readAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::ensureReachable(const FilePath &other) const
|
bool FilePath::ensureReachable(const FilePath &other) const
|
||||||
@@ -577,78 +473,30 @@ bool FilePath::ensureReachable(const FilePath &other) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FilePath::asyncFileContents(
|
||||||
void FilePath::asyncFileContents(const Continuation<const std::optional<QByteArray> &> &cont,
|
const Continuation<const std::optional<QByteArray> &> &cont,
|
||||||
qint64 maxSize,
|
qint64 maxSize,
|
||||||
qint64 offset) const
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->asyncFileContents(*this, cont, maxSize, offset);
|
||||||
QTC_ASSERT(s_deviceHooks.asyncFileContents, return);
|
|
||||||
s_deviceHooks.asyncFileContents(cont, *this, maxSize, offset);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cont(fileContents(maxSize, offset));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::writeFileContents(const QByteArray &data, qint64 offset) const
|
bool FilePath::writeFileContents(const QByteArray &data, qint64 offset) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->writeFileContents(*this, data, offset);
|
||||||
QTC_ASSERT(s_deviceHooks.writeFileContents, return {});
|
|
||||||
return s_deviceHooks.writeFileContents(*this, data, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
QFile file(path());
|
|
||||||
QTC_ASSERT(file.open(QFile::WriteOnly | QFile::Truncate), return false);
|
|
||||||
if (offset != 0)
|
|
||||||
file.seek(offset);
|
|
||||||
qint64 res = file.write(data);
|
|
||||||
return res == data.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePathInfo FilePath::filePathInfo() const
|
FilePathInfo FilePath::filePathInfo() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->filePathInfo(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.filePathInfo, return {});
|
|
||||||
return s_deviceHooks.filePathInfo(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePathInfo result;
|
|
||||||
|
|
||||||
QFileInfo fi(path());
|
|
||||||
result.fileSize = fi.size();
|
|
||||||
result.lastModified = fi.lastModified();
|
|
||||||
result.fileFlags = (FilePathInfo::FileFlag) int(fi.permissions());
|
|
||||||
|
|
||||||
if (fi.isDir())
|
|
||||||
result.fileFlags |= FilePathInfo::DirectoryType;
|
|
||||||
if (fi.isFile())
|
|
||||||
result.fileFlags |= FilePathInfo::FileType;
|
|
||||||
if (fi.exists())
|
|
||||||
result.fileFlags |= FilePathInfo::ExistsFlag;
|
|
||||||
if (fi.isSymbolicLink())
|
|
||||||
result.fileFlags |= FilePathInfo::LinkType;
|
|
||||||
if (fi.isBundle())
|
|
||||||
result.fileFlags |= FilePathInfo::BundleType;
|
|
||||||
if (fi.isHidden())
|
|
||||||
result.fileFlags |= FilePathInfo::HiddenFlag;
|
|
||||||
if (fi.isRoot())
|
|
||||||
result.fileFlags |= FilePathInfo::RootFlag;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilePath::asyncWriteFileContents(const Continuation<bool> &cont,
|
void FilePath::asyncWriteFileContents(
|
||||||
const QByteArray &data,
|
const Continuation<bool> &cont,
|
||||||
qint64 offset) const
|
const QByteArray &data,
|
||||||
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->asyncWriteFileContents(*this, cont, data, offset);
|
||||||
QTC_ASSERT(s_deviceHooks.asyncWriteFileContents, return);
|
|
||||||
s_deviceHooks.asyncWriteFileContents(cont, *this, data, offset);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cont(writeFileContents(data, offset));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::needsDevice() const
|
bool FilePath::needsDevice() const
|
||||||
@@ -670,23 +518,12 @@ bool FilePath::isSameDevice(const FilePath &other) const
|
|||||||
/// \returns an empty FilePath if this is not a symbolic linl
|
/// \returns an empty FilePath if this is not a symbolic linl
|
||||||
FilePath FilePath::symLinkTarget() const
|
FilePath FilePath::symLinkTarget() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->symLinkTarget(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.symLinkTarget, return {});
|
|
||||||
return s_deviceHooks.symLinkTarget(*this);
|
|
||||||
}
|
|
||||||
const QFileInfo info(path());
|
|
||||||
if (!info.isSymLink())
|
|
||||||
return {};
|
|
||||||
return FilePath::fromString(info.symLinkTarget());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FilePath::mapToDevicePath() const
|
QString FilePath::mapToDevicePath() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->mapToDevicePath(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.mapToDevicePath, return path());
|
|
||||||
return s_deviceHooks.mapToDevicePath(*this);
|
|
||||||
}
|
|
||||||
return path();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath FilePath::withExecutableSuffix() const
|
FilePath FilePath::withExecutableSuffix() const
|
||||||
@@ -937,6 +774,23 @@ void FilePath::setFromString(const QString &unnormalizedFileName)
|
|||||||
setParts({}, {}, fileName);
|
setParts({}, {}, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeviceFileAccess *FilePath::fileAccess() const
|
||||||
|
{
|
||||||
|
if (!needsDevice())
|
||||||
|
return DesktopDeviceFileAccess::instance();
|
||||||
|
|
||||||
|
if (!s_deviceHooks.fileAccess) {
|
||||||
|
// Happens during startup and in tst_fsengine
|
||||||
|
QTC_CHECK(false);
|
||||||
|
return DesktopDeviceFileAccess::instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
static DeviceFileAccess dummy;
|
||||||
|
DeviceFileAccess *access = s_deviceHooks.fileAccess(*this);
|
||||||
|
QTC_ASSERT(access, return &dummy);
|
||||||
|
return access;
|
||||||
|
}
|
||||||
|
|
||||||
/// Constructs a FilePath from \a filePath. The \a defaultExtension is appended
|
/// Constructs a FilePath from \a filePath. The \a defaultExtension is appended
|
||||||
/// to \a filename if that does not have an extension already.
|
/// to \a filename if that does not have an extension already.
|
||||||
/// \a filePath is not checked for validity.
|
/// \a filePath is not checked for validity.
|
||||||
@@ -1241,10 +1095,10 @@ FilePath FilePath::withNewPath(const QString &newPath) const
|
|||||||
*/
|
*/
|
||||||
FilePath FilePath::searchInDirectories(const FilePaths &dirs) const
|
FilePath FilePath::searchInDirectories(const FilePaths &dirs) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
if (isAbsolutePath())
|
||||||
QTC_ASSERT(s_deviceHooks.searchInPath, return {});
|
return *this;
|
||||||
return s_deviceHooks.searchInPath(*this, dirs);
|
// FIXME: Ramp down use.
|
||||||
}
|
QTC_ASSERT(!needsDevice(), return {});
|
||||||
return Environment::systemEnvironment().searchInDirectories(path(), dirs);
|
return Environment::systemEnvironment().searchInDirectories(path(), dirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1252,6 +1106,7 @@ FilePath FilePath::searchInPath(const FilePaths &additionalDirs, PathAmending am
|
|||||||
{
|
{
|
||||||
if (isAbsolutePath())
|
if (isAbsolutePath())
|
||||||
return *this;
|
return *this;
|
||||||
|
// FIXME: Ramp down use.
|
||||||
FilePaths directories = deviceEnvironment().path();
|
FilePaths directories = deviceEnvironment().path();
|
||||||
if (!additionalDirs.isEmpty()) {
|
if (!additionalDirs.isEmpty()) {
|
||||||
if (amending == AppendToPath)
|
if (amending == AppendToPath)
|
||||||
@@ -1259,7 +1114,8 @@ FilePath FilePath::searchInPath(const FilePaths &additionalDirs, PathAmending am
|
|||||||
else
|
else
|
||||||
directories = additionalDirs + directories;
|
directories = additionalDirs + directories;
|
||||||
}
|
}
|
||||||
return searchInDirectories(directories);
|
QTC_ASSERT(!needsDevice(), return {});
|
||||||
|
return Environment::systemEnvironment().searchInDirectories(path(), directories);
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment FilePath::deviceEnvironment() const
|
Environment FilePath::deviceEnvironment() const
|
||||||
@@ -1338,47 +1194,27 @@ size_t FilePath::hash(uint seed) const
|
|||||||
|
|
||||||
QDateTime FilePath::lastModified() const
|
QDateTime FilePath::lastModified() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->lastModified(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.lastModified, return {});
|
|
||||||
return s_deviceHooks.lastModified(*this);
|
|
||||||
}
|
|
||||||
return toFileInfo().lastModified();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile::Permissions FilePath::permissions() const
|
QFile::Permissions FilePath::permissions() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->permissions(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.permissions, return {});
|
|
||||||
return s_deviceHooks.permissions(*this);
|
|
||||||
}
|
|
||||||
return toFileInfo().permissions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::setPermissions(QFile::Permissions permissions) const
|
bool FilePath::setPermissions(QFile::Permissions permissions) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->setPermissions(*this, permissions);
|
||||||
QTC_ASSERT(s_deviceHooks.setPermissions, return false);
|
|
||||||
return s_deviceHooks.setPermissions(*this, permissions);
|
|
||||||
}
|
|
||||||
return QFile(path()).setPermissions(permissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OsType FilePath::osType() const
|
OsType FilePath::osType() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->osType(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.osType, return OsType::OsTypeLinux);
|
|
||||||
return s_deviceHooks.osType(*this);
|
|
||||||
}
|
|
||||||
return HostOsInfo::hostOs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::removeFile() const
|
bool FilePath::removeFile() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->removeFile(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.removeFile, return false);
|
|
||||||
return s_deviceHooks.removeFile(*this);
|
|
||||||
}
|
|
||||||
return QFile::remove(path());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -1390,11 +1226,7 @@ bool FilePath::removeFile() const
|
|||||||
*/
|
*/
|
||||||
bool FilePath::removeRecursively(QString *error) const
|
bool FilePath::removeRecursively(QString *error) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->removeRecursively(*this, error);
|
||||||
QTC_ASSERT(s_deviceHooks.removeRecursively, return false);
|
|
||||||
return s_deviceHooks.removeRecursively(*this);
|
|
||||||
}
|
|
||||||
return removeRecursivelyLocal(*this, error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::copyFile(const FilePath &target) const
|
bool FilePath::copyFile(const FilePath &target) const
|
||||||
@@ -1406,11 +1238,7 @@ bool FilePath::copyFile(const FilePath &target) const
|
|||||||
return false;
|
return false;
|
||||||
return target.writeFileContents(*ba);
|
return target.writeFileContents(*ba);
|
||||||
}
|
}
|
||||||
if (needsDevice()) {
|
return fileAccess()->copyFile(*this, target);
|
||||||
QTC_ASSERT(s_deviceHooks.copyFile, return false);
|
|
||||||
return s_deviceHooks.copyFile(*this, target);
|
|
||||||
}
|
|
||||||
return QFile::copy(path(), target.path());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilePath::asyncCopyFile(const std::function<void(bool)> &cont, const FilePath &target) const
|
void FilePath::asyncCopyFile(const std::function<void(bool)> &cont, const FilePath &target) const
|
||||||
@@ -1420,90 +1248,24 @@ void FilePath::asyncCopyFile(const std::function<void(bool)> &cont, const FilePa
|
|||||||
if (ba)
|
if (ba)
|
||||||
target.asyncWriteFileContents(cont, *ba);
|
target.asyncWriteFileContents(cont, *ba);
|
||||||
});
|
});
|
||||||
} else if (needsDevice()) {
|
return;
|
||||||
s_deviceHooks.asyncCopyFile(cont, *this, target);
|
|
||||||
} else {
|
|
||||||
cont(copyFile(target));
|
|
||||||
}
|
}
|
||||||
|
return fileAccess()->asyncCopyFile(*this, cont, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilePath::renameFile(const FilePath &target) const
|
bool FilePath::renameFile(const FilePath &target) const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->renameFile(*this, target);
|
||||||
QTC_ASSERT(s_deviceHooks.renameFile, return false);
|
|
||||||
return s_deviceHooks.renameFile(*this, target);
|
|
||||||
}
|
|
||||||
return QFile::rename(path(), target.path());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 FilePath::fileSize() const
|
qint64 FilePath::fileSize() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->fileSize(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.fileSize, return false);
|
|
||||||
return s_deviceHooks.fileSize(*this);
|
|
||||||
}
|
|
||||||
return QFileInfo(path()).size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 FilePath::bytesAvailable() const
|
qint64 FilePath::bytesAvailable() const
|
||||||
{
|
{
|
||||||
if (needsDevice()) {
|
return fileAccess()->bytesAvailable(*this);
|
||||||
QTC_ASSERT(s_deviceHooks.bytesAvailable, return false);
|
|
||||||
return s_deviceHooks.bytesAvailable(*this);
|
|
||||||
}
|
|
||||||
return QStorageInfo(path()).bytesAvailable();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool removeRecursivelyLocal(const FilePath &filePath, QString *error)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(!filePath.needsDevice(), return false);
|
|
||||||
QFileInfo fileInfo = filePath.toFileInfo();
|
|
||||||
if (!fileInfo.exists() && !fileInfo.isSymLink())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
QFile::setPermissions(fileInfo.absoluteFilePath(), fileInfo.permissions() | QFile::WriteUser);
|
|
||||||
|
|
||||||
if (fileInfo.isDir()) {
|
|
||||||
QDir dir(fileInfo.absoluteFilePath());
|
|
||||||
dir.setPath(dir.canonicalPath());
|
|
||||||
if (dir.isRoot()) {
|
|
||||||
if (error) {
|
|
||||||
*error = QCoreApplication::translate("Utils::FileUtils",
|
|
||||||
"Refusing to remove root directory.");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (dir.path() == QDir::home().canonicalPath()) {
|
|
||||||
if (error) {
|
|
||||||
*error = QCoreApplication::translate("Utils::FileUtils",
|
|
||||||
"Refusing to remove your home directory.");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QStringList fileNames = dir.entryList(
|
|
||||||
QDir::Files | QDir::Hidden | QDir::System | QDir::Dirs | QDir::NoDotAndDotDot);
|
|
||||||
for (const QString &fileName : fileNames) {
|
|
||||||
if (!removeRecursivelyLocal(filePath / fileName, error))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!QDir::root().rmdir(dir.path())) {
|
|
||||||
if (error) {
|
|
||||||
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to remove directory \"%1\".")
|
|
||||||
.arg(filePath.toUserOutput());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!QFile::remove(filePath.toString())) {
|
|
||||||
if (error) {
|
|
||||||
*error = QCoreApplication::translate("Utils::FileUtils", "Failed to remove file \"%1\".")
|
|
||||||
.arg(filePath.toUserOutput());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -28,9 +28,12 @@ class tst_fileutils; // This becomes a friend of Utils::FilePath for testing pri
|
|||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
|
class DeviceFileAccess;
|
||||||
class Environment;
|
class Environment;
|
||||||
class EnvironmentChange;
|
class EnvironmentChange;
|
||||||
|
|
||||||
|
template <class ...Args> using Continuation = std::function<void(Args...)>;
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT FileFilter
|
class QTCREATOR_UTILS_EXPORT FileFilter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -188,7 +191,6 @@ public:
|
|||||||
static void sort(FilePaths &files);
|
static void sort(FilePaths &files);
|
||||||
|
|
||||||
// Asynchronous interface
|
// Asynchronous interface
|
||||||
template <class ...Args> using Continuation = std::function<void(Args...)>;
|
|
||||||
void asyncCopyFile(const Continuation<bool> &cont, const FilePath &target) const;
|
void asyncCopyFile(const Continuation<bool> &cont, const FilePath &target) const;
|
||||||
void asyncFileContents(const Continuation<const std::optional<QByteArray> &> &cont,
|
void asyncFileContents(const Continuation<const std::optional<QByteArray> &> &cont,
|
||||||
qint64 maxSize = -1,
|
qint64 maxSize = -1,
|
||||||
@@ -232,6 +234,7 @@ private:
|
|||||||
static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);
|
static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);
|
||||||
void setPath(QStringView path);
|
void setPath(QStringView path);
|
||||||
void setFromString(const QString &filepath);
|
void setFromString(const QString &filepath);
|
||||||
|
DeviceFileAccess *fileAccess() const;
|
||||||
|
|
||||||
[[nodiscard]] QString mapToDevicePath() const;
|
[[nodiscard]] QString mapToDevicePath() const;
|
||||||
[[nodiscard]] QString encodedHost() const;
|
[[nodiscard]] QString encodedHost() const;
|
||||||
@@ -252,50 +255,11 @@ class QTCREATOR_UTILS_EXPORT DeviceFileHooks
|
|||||||
public:
|
public:
|
||||||
static DeviceFileHooks &instance();
|
static DeviceFileHooks &instance();
|
||||||
|
|
||||||
std::function<bool(const FilePath &)> isExecutableFile;
|
std::function<DeviceFileAccess *(const FilePath &)> fileAccess;
|
||||||
std::function<bool(const FilePath &)> isReadableFile;
|
|
||||||
std::function<bool(const FilePath &)> isReadableDir;
|
|
||||||
std::function<bool(const FilePath &)> isWritableDir;
|
|
||||||
std::function<bool(const FilePath &)> isWritableFile;
|
|
||||||
std::function<bool(const FilePath &)> isFile;
|
|
||||||
std::function<bool(const FilePath &)> isDir;
|
|
||||||
std::function<bool(const FilePath &)> ensureWritableDir;
|
|
||||||
std::function<bool(const FilePath &)> ensureExistingFile;
|
|
||||||
std::function<bool(const FilePath &)> createDir;
|
|
||||||
std::function<bool(const FilePath &)> exists;
|
|
||||||
std::function<bool(const FilePath &)> removeFile;
|
|
||||||
std::function<bool(const FilePath &)> removeRecursively;
|
|
||||||
std::function<bool(const FilePath &, const FilePath &)> copyFile;
|
|
||||||
std::function<bool(const FilePath &, const FilePath &)> renameFile;
|
|
||||||
std::function<FilePath(const FilePath &, const FilePaths &)> searchInPath;
|
|
||||||
std::function<FilePath(const FilePath &)> symLinkTarget;
|
|
||||||
std::function<QString(const FilePath &)> mapToDevicePath;
|
|
||||||
std::function<void(const FilePath &,
|
|
||||||
const FilePath::IterateDirCallback &, // Abort on 'false' return.
|
|
||||||
const FileFilter &)>
|
|
||||||
iterateDirectory;
|
|
||||||
std::function<std::optional<QByteArray>(const FilePath &, qint64, qint64)> fileContents;
|
|
||||||
std::function<bool(const FilePath &, const QByteArray &, qint64)> writeFileContents;
|
|
||||||
std::function<QDateTime(const FilePath &)> lastModified;
|
|
||||||
std::function<QFile::Permissions(const FilePath &)> permissions;
|
|
||||||
std::function<bool(const FilePath &, QFile::Permissions)> setPermissions;
|
|
||||||
std::function<OsType(const FilePath &)> osType;
|
|
||||||
std::function<Environment(const FilePath &)> environment;
|
|
||||||
std::function<qint64(const FilePath &)> fileSize;
|
|
||||||
std::function<qint64(const FilePath &)> bytesAvailable;
|
|
||||||
std::function<QString(const FilePath &)> deviceDisplayName;
|
std::function<QString(const FilePath &)> deviceDisplayName;
|
||||||
std::function<bool(const FilePath &, const FilePath &)> isSameDevice;
|
|
||||||
std::function<FilePathInfo(const FilePath &)> filePathInfo;
|
|
||||||
|
|
||||||
|
|
||||||
template <class ...Args> using Continuation = std::function<void(Args...)>;
|
|
||||||
std::function<void(const Continuation<bool> &, const FilePath &, const FilePath &)> asyncCopyFile;
|
|
||||||
std::function<void(
|
|
||||||
const Continuation<const std::optional<QByteArray> &> &, const FilePath &, qint64, qint64)>
|
|
||||||
asyncFileContents;
|
|
||||||
std::function<void(const Continuation<bool> &, const FilePath &, const QByteArray &, qint64)>
|
|
||||||
asyncWriteFileContents;
|
|
||||||
std::function<bool(const FilePath &, const FilePath &)> ensureReachable;
|
std::function<bool(const FilePath &, const FilePath &)> ensureReachable;
|
||||||
|
std::function<Environment(const FilePath &)> environment;
|
||||||
|
std::function<bool(const FilePath &left, const FilePath &right)> isSameDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|||||||
@@ -646,46 +646,6 @@ FilePaths FileUtils::getOpenFilePaths(QWidget *parent,
|
|||||||
|
|
||||||
#endif // QT_WIDGETS_LIB
|
#endif // QT_WIDGETS_LIB
|
||||||
|
|
||||||
// Used on 'ls' output on unix-like systems.
|
|
||||||
static void iterateLsOutput(const FilePath &base,
|
|
||||||
const QStringList &entries,
|
|
||||||
const FileFilter &filter,
|
|
||||||
const FilePath::IterateDirCallback &callBack)
|
|
||||||
{
|
|
||||||
const QList<QRegularExpression> nameRegexps =
|
|
||||||
transform(filter.nameFilters, [](const QString &filter) {
|
|
||||||
QRegularExpression re;
|
|
||||||
re.setPattern(QRegularExpression::wildcardToRegularExpression(filter));
|
|
||||||
QTC_CHECK(re.isValid());
|
|
||||||
return re;
|
|
||||||
});
|
|
||||||
|
|
||||||
const auto nameMatches = [&nameRegexps](const QString &fileName) {
|
|
||||||
for (const QRegularExpression &re : nameRegexps) {
|
|
||||||
const QRegularExpressionMatch match = re.match(fileName);
|
|
||||||
if (match.hasMatch())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return nameRegexps.isEmpty();
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: Handle filters. For now bark on unsupported options.
|
|
||||||
QTC_CHECK(filter.fileFilters == QDir::NoFilter);
|
|
||||||
|
|
||||||
for (const QString &entry : entries) {
|
|
||||||
if (!nameMatches(entry))
|
|
||||||
continue;
|
|
||||||
const FilePath current = base.pathAppended(entry);
|
|
||||||
bool res = false;
|
|
||||||
if (callBack.index() == 0)
|
|
||||||
res = std::get<0>(callBack)(current);
|
|
||||||
else
|
|
||||||
res = std::get<1>(callBack)(current, current.filePathInfo());
|
|
||||||
if (!res)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePathInfo::FileFlags fileInfoFlagsfromStatRawModeHex(const QString &hexString)
|
FilePathInfo::FileFlags fileInfoFlagsfromStatRawModeHex(const QString &hexString)
|
||||||
{
|
{
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
@@ -741,120 +701,6 @@ FilePathInfo FileUtils::filePathInfoFromTriple(const QString &infos)
|
|||||||
return {size, flags, dt};
|
return {size, flags, dt};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool iterateWithFindHelper(
|
|
||||||
const FilePath &filePath,
|
|
||||||
const FileFilter &filter,
|
|
||||||
const std::function<RunResult(const CommandLine &)> &runInShell,
|
|
||||||
const std::function<bool(const QString &)> callBack,
|
|
||||||
const QString &extraArguments)
|
|
||||||
{
|
|
||||||
QTC_CHECK(filePath.isAbsolutePath());
|
|
||||||
const QStringList arguments = filter.asFindArguments(filePath.path());
|
|
||||||
|
|
||||||
CommandLine cmdLine{"find", arguments};
|
|
||||||
if (!extraArguments.isEmpty())
|
|
||||||
cmdLine.addArgs(extraArguments, CommandLine::Raw);
|
|
||||||
|
|
||||||
const RunResult result = runInShell(cmdLine);
|
|
||||||
const QString out = QString::fromUtf8(result.stdOut);
|
|
||||||
if (result.exitCode != 0) {
|
|
||||||
// Find returns non-zero exit code for any error it encounters, even if it finds some files.
|
|
||||||
|
|
||||||
if (!out.startsWith('"' + filePath.path())) {
|
|
||||||
if (!filePath.exists()) // File does not exist, so no files to find.
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// If the output does not start with the path we are searching in, find has failed.
|
|
||||||
// Possibly due to unknown options.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList entries = out.split("\n", Qt::SkipEmptyParts);
|
|
||||||
if (entries.isEmpty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Remove the first line, it is always the directory we are searching in.
|
|
||||||
// as long as we do not specify "mindepth > 0"
|
|
||||||
if (entries.size() > 0)
|
|
||||||
entries.pop_front();
|
|
||||||
for (const QString &entry : entries) {
|
|
||||||
if (!callBack(entry))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns whether 'find' could be used.
|
|
||||||
static bool iterateWithFind(
|
|
||||||
const FilePath &filePath,
|
|
||||||
const FileFilter &filter,
|
|
||||||
const std::function<RunResult(const CommandLine &)> &runInShell,
|
|
||||||
const FilePath::IterateDirCallback &callBack)
|
|
||||||
{
|
|
||||||
const auto toFilePath = [&filePath, &callBack](const QString &entry) {
|
|
||||||
if (callBack.index() == 0)
|
|
||||||
return std::get<0>(callBack)(filePath.withNewPath(entry));
|
|
||||||
|
|
||||||
const QString fileName = entry.mid(1, entry.lastIndexOf('\"') - 1);
|
|
||||||
const QString infos = entry.mid(fileName.length() + 3);
|
|
||||||
|
|
||||||
const FilePathInfo fi = FileUtils::filePathInfoFromTriple(infos);
|
|
||||||
if (!fi.fileFlags)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
const FilePath fp = filePath.withNewPath(fileName);
|
|
||||||
return std::get<1>(callBack)(fp, fi);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Using stat -L will always return the link target, not the link itself.
|
|
||||||
// We may wan't to add the information that it is a link at some point.
|
|
||||||
QString infoArgs;
|
|
||||||
if (callBack.index() == 1)
|
|
||||||
infoArgs = R"(-exec echo -n \"{}\"" " \; -exec stat -L -c "%f %Y %s" "{}" \;)";
|
|
||||||
|
|
||||||
return iterateWithFindHelper(filePath, filter, runInShell, toFilePath, infoArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void findUsingLs(const QString ¤t,
|
|
||||||
const FileFilter &filter,
|
|
||||||
const std::function<RunResult(const CommandLine &)> &runInShell,
|
|
||||||
QStringList *found)
|
|
||||||
{
|
|
||||||
const RunResult result = runInShell({"ls", {"-1", "-p", "--", current}});
|
|
||||||
const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts);
|
|
||||||
for (QString entry : entries) {
|
|
||||||
const QChar last = entry.back();
|
|
||||||
if (last == '/') {
|
|
||||||
entry.chop(1);
|
|
||||||
if (filter.iteratorFlags.testFlag(QDirIterator::Subdirectories))
|
|
||||||
findUsingLs(current + '/' + entry, filter, runInShell, found);
|
|
||||||
}
|
|
||||||
found->append(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileUtils::iterateUnixDirectory(const FilePath &filePath,
|
|
||||||
const FileFilter &filter,
|
|
||||||
bool *useFind,
|
|
||||||
const std::function<RunResult (const CommandLine &)> &runInShell,
|
|
||||||
const FilePath::IterateDirCallback &callBack)
|
|
||||||
{
|
|
||||||
// We try to use 'find' first, because that can filter better directly.
|
|
||||||
// Unfortunately, it's not installed on all devices by default.
|
|
||||||
if (useFind && *useFind) {
|
|
||||||
if (iterateWithFind(filePath, filter, runInShell, callBack))
|
|
||||||
return;
|
|
||||||
*useFind = false; // remember the failure for the next time and use the 'ls' fallback below.
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we do not have find - use ls as fallback
|
|
||||||
QStringList entries;
|
|
||||||
findUsingLs(filePath.path(), filter, runInShell, &entries);
|
|
||||||
iterateLsOutput(filePath, entries, filter, callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Copies the directory specified by \a srcFilePath recursively to \a tgtFilePath. \a tgtFilePath will contain
|
Copies the directory specified by \a srcFilePath recursively to \a tgtFilePath. \a tgtFilePath will contain
|
||||||
the target directory, which will be created. Example usage:
|
the target directory, which will be created. Example usage:
|
||||||
|
|||||||
@@ -86,13 +86,6 @@ public:
|
|||||||
|
|
||||||
static FilePaths toFilePathList(const QStringList &paths);
|
static FilePaths toFilePathList(const QStringList &paths);
|
||||||
|
|
||||||
static void iterateUnixDirectory(
|
|
||||||
const FilePath &base,
|
|
||||||
const FileFilter &filter,
|
|
||||||
bool *useFind,
|
|
||||||
const std::function<RunResult(const CommandLine &)> &runInShell,
|
|
||||||
const FilePath::IterateDirCallback &callBack);
|
|
||||||
|
|
||||||
static qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput);
|
static qint64 bytesAvailableFromDFOutput(const QByteArray &dfOutput);
|
||||||
|
|
||||||
static FilePathInfo filePathInfoFromTriple(const QString &infos);
|
static FilePathInfo filePathInfoFromTriple(const QString &infos);
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ Project {
|
|||||||
"detailsbutton.h",
|
"detailsbutton.h",
|
||||||
"detailswidget.cpp",
|
"detailswidget.cpp",
|
||||||
"detailswidget.h",
|
"detailswidget.h",
|
||||||
|
"devicefileaccess.cpp",
|
||||||
|
"devicefileaccess.h",
|
||||||
"deviceshell.cpp",
|
"deviceshell.cpp",
|
||||||
"deviceshell.h",
|
"deviceshell.h",
|
||||||
"differ.cpp",
|
"differ.cpp",
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/basetreeview.h>
|
#include <utils/basetreeview.h>
|
||||||
|
#include <utils/devicefileaccess.h>
|
||||||
#include <utils/deviceshell.h>
|
#include <utils/deviceshell.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
@@ -113,6 +114,25 @@ private:
|
|||||||
FilePath m_devicePath;
|
FilePath m_devicePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DockerDeviceFileAccess : public UnixDeviceFileAccess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DockerDeviceFileAccess(DockerDevicePrivate *dev)
|
||||||
|
: m_dev(dev)
|
||||||
|
{}
|
||||||
|
|
||||||
|
RunResult runInShell(const QString &executable,
|
||||||
|
const QStringList &arguments,
|
||||||
|
const QByteArray &stdInData) const override;
|
||||||
|
|
||||||
|
std::optional<QByteArray> fileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const override;
|
||||||
|
|
||||||
|
DockerDevicePrivate *m_dev = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
class DockerDevicePrivate : public QObject
|
class DockerDevicePrivate : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -129,8 +149,6 @@ public:
|
|||||||
return runInShell(cmd, stdInData).exitCode == 0;
|
return runInShell(cmd, stdInData).exitCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QByteArray> fileContents(const FilePath &filePath, qint64 limit, qint64 offset);
|
|
||||||
|
|
||||||
void updateContainerAccess();
|
void updateContainerAccess();
|
||||||
void changeMounts(QStringList newMounts);
|
void changeMounts(QStringList newMounts);
|
||||||
bool ensureReachable(const FilePath &other);
|
bool ensureReachable(const FilePath &other);
|
||||||
@@ -177,8 +195,8 @@ public:
|
|||||||
QString m_container;
|
QString m_container;
|
||||||
|
|
||||||
Environment m_cachedEnviroment;
|
Environment m_cachedEnviroment;
|
||||||
bool m_useFind = true; // prefer find over ls and hacks, but be able to use ls as fallback
|
|
||||||
bool m_isShutdown = false;
|
bool m_isShutdown = false;
|
||||||
|
DockerDeviceFileAccess m_fileAccess{this};
|
||||||
};
|
};
|
||||||
|
|
||||||
class DockerProcessImpl : public Utils::ProcessInterface
|
class DockerProcessImpl : public Utils::ProcessInterface
|
||||||
@@ -337,9 +355,28 @@ Tasks DockerDevicePrivate::validateMounts() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RunResult DockerDeviceFileAccess::runInShell(
|
||||||
|
const QString &executable,
|
||||||
|
const QStringList &arguments,
|
||||||
|
const QByteArray &stdInData) const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_dev, return {});
|
||||||
|
return m_dev->runInShell({FilePath::fromString(executable), arguments}, stdInData);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<QByteArray> DockerDeviceFileAccess::fileContents(
|
||||||
|
const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
|
{
|
||||||
|
m_dev->updateContainerAccess();
|
||||||
|
return UnixDeviceFileAccess::fileContents(filePath, limit, offset);
|
||||||
|
}
|
||||||
|
|
||||||
DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &data)
|
DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &data)
|
||||||
: d(new DockerDevicePrivate(this, settings, data))
|
: d(new DockerDevicePrivate(this, settings, data))
|
||||||
{
|
{
|
||||||
|
setFileAccess(&d->m_fileAccess);
|
||||||
setDisplayType(Tr::tr("Docker"));
|
setDisplayType(Tr::tr("Docker"));
|
||||||
setOsType(OsTypeOtherUnix);
|
setOsType(OsTypeOtherUnix);
|
||||||
setDefaultDisplayName(Tr::tr("Docker Image"));
|
setDefaultDisplayName(Tr::tr("Docker Image"));
|
||||||
@@ -778,165 +815,6 @@ bool DockerDevice::handlesFile(const FilePath &filePath) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DockerDevice::isExecutableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-x", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::isReadableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-r", path, "-a", "-f", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::isWritableFile(const Utils::FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-w", path, "-a", "-f", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::isReadableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-r", path, "-a", "-d", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::isWritableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-w", path, "-a", "-d", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::isFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-f", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::isDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-d", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::createDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"mkdir", {"-p", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::exists(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-e", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::ensureExistingFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"touch", {path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::removeFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return d->runInShellSuccess({"rm", {filePath.path()}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::removeRecursively(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
QTC_ASSERT(filePath.path().startsWith('/'), return false);
|
|
||||||
|
|
||||||
const QString path = filePath.cleanPath().path();
|
|
||||||
// We are expecting this only to be called in a context of build directories or similar.
|
|
||||||
// Chicken out in some cases that _might_ be user code errors.
|
|
||||||
QTC_ASSERT(path.startsWith('/'), return false);
|
|
||||||
const int levelsNeeded = path.startsWith("/home/") ? 4 : 3;
|
|
||||||
QTC_ASSERT(path.count('/') >= levelsNeeded, return false);
|
|
||||||
|
|
||||||
return d->runInShellSuccess({"rm", {"-rf", "--", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::copyFile(const FilePath &filePath, const FilePath &target) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
|
||||||
return d->runInShellSuccess({"cp", {filePath.path(), target.path()}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::renameFile(const FilePath &filePath, const FilePath &target) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
|
||||||
return d->runInShellSuccess({"mv", {filePath.path(), target.path()}});
|
|
||||||
}
|
|
||||||
|
|
||||||
QDateTime DockerDevice::lastModified(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%Y", filePath.path()}});
|
|
||||||
qint64 secs = result.stdOut.toLongLong();
|
|
||||||
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath DockerDevice::symLinkTarget(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
const RunResult result = d->runInShell({"readlink", {"-n", "-e", filePath.path()}});
|
|
||||||
const QString out = QString::fromUtf8(result.stdOut);
|
|
||||||
return out.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 DockerDevice::fileSize(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
|
||||||
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%s", filePath.path()}});
|
|
||||||
return result.stdOut.toLongLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileDevice::Permissions DockerDevice::permissions(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
|
|
||||||
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%a", filePath.path()}});
|
|
||||||
const uint bits = result.stdOut.toUInt(nullptr, 8);
|
|
||||||
QFileDevice::Permissions perm = {};
|
|
||||||
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
|
||||||
BIT(0, ExeOther);
|
|
||||||
BIT(1, WriteOther);
|
|
||||||
BIT(2, ReadOther);
|
|
||||||
BIT(3, ExeGroup);
|
|
||||||
BIT(4, WriteGroup);
|
|
||||||
BIT(5, ReadGroup);
|
|
||||||
BIT(6, ExeUser);
|
|
||||||
BIT(7, WriteUser);
|
|
||||||
BIT(8, ReadUser);
|
|
||||||
#undef BIT
|
|
||||||
return perm;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::setPermissions(const FilePath &filePath,
|
|
||||||
QFileDevice::Permissions permissions) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(permissions)
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
QTC_CHECK(false); // FIXME: Implement.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::ensureReachable(const FilePath &other) const
|
bool DockerDevice::ensureReachable(const FilePath &other) const
|
||||||
{
|
{
|
||||||
if (other.needsDevice())
|
if (other.needsDevice())
|
||||||
@@ -947,43 +825,6 @@ bool DockerDevice::ensureReachable(const FilePath &other) const
|
|||||||
return d->ensureReachable(other.parentDir());
|
return d->ensureReachable(other.parentDir());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DockerDevice::iterateDirectory(const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
|
||||||
const FileFilter &filter) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return);
|
|
||||||
auto runInShell = [this](const CommandLine &cmd) { return d->runInShell(cmd); };
|
|
||||||
FileUtils::iterateUnixDirectory(filePath, filter, &d->m_useFind, runInShell, callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<QByteArray> DockerDevice::fileContents(const FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
return d->fileContents(filePath, limit, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DockerDevice::writeFileContents(const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
CommandLine cmd({"dd", {"of=" + filePath.path()}});
|
|
||||||
if (offset != 0) {
|
|
||||||
cmd.addArg("bs=1");
|
|
||||||
cmd.addArg(QString("seek=%1").arg(offset));
|
|
||||||
}
|
|
||||||
return d->runInShellSuccess(cmd, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePathInfo DockerDevice::filePathInfo(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
const RunResult stat = d->runInShell({"stat", {"-L", "-c", "%f %Y %s", filePath.path()}});
|
|
||||||
return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut));
|
|
||||||
}
|
|
||||||
|
|
||||||
Environment DockerDevice::systemEnvironment() const
|
Environment DockerDevice::systemEnvironment() const
|
||||||
{
|
{
|
||||||
return d->environment();
|
return d->environment();
|
||||||
@@ -995,28 +836,6 @@ void DockerDevice::aboutToBeRemoved() const
|
|||||||
detector.undoAutoDetect(id().toString());
|
detector.undoAutoDetect(id().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QByteArray> DockerDevicePrivate::fileContents(const FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset)
|
|
||||||
{
|
|
||||||
updateContainerAccess();
|
|
||||||
|
|
||||||
QStringList args = {"if=" + filePath.path(), "status=none"};
|
|
||||||
if (limit > 0 || offset > 0) {
|
|
||||||
const qint64 gcd = std::gcd(limit, offset);
|
|
||||||
args += {QString("bs=%1").arg(gcd),
|
|
||||||
QString("count=%1").arg(limit / gcd),
|
|
||||||
QString("seek=%1").arg(offset / gcd)};
|
|
||||||
}
|
|
||||||
|
|
||||||
const RunResult r = m_shell->runInShell({"dd", args});
|
|
||||||
|
|
||||||
if (r.exitCode != 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
return r.stdOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DockerDevicePrivate::fetchSystemEnviroment()
|
void DockerDevicePrivate::fetchSystemEnviroment()
|
||||||
{
|
{
|
||||||
updateContainerAccess();
|
updateContainerAccess();
|
||||||
|
|||||||
@@ -84,37 +84,6 @@ public:
|
|||||||
Utils::FilePath rootPath() const override;
|
Utils::FilePath rootPath() const override;
|
||||||
|
|
||||||
bool handlesFile(const Utils::FilePath &filePath) const override;
|
bool handlesFile(const Utils::FilePath &filePath) const override;
|
||||||
bool isExecutableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isReadableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isWritableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isReadableDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isWritableDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool createDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool exists(const Utils::FilePath &filePath) const override;
|
|
||||||
bool ensureExistingFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool removeFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool removeRecursively(const Utils::FilePath &filePath) const override;
|
|
||||||
bool copyFile(const Utils::FilePath &filePath, const Utils::FilePath &target) const override;
|
|
||||||
bool renameFile(const Utils::FilePath &filePath, const Utils::FilePath &target) const override;
|
|
||||||
Utils::FilePath symLinkTarget(const Utils::FilePath &filePath) const override;
|
|
||||||
void iterateDirectory(
|
|
||||||
const Utils::FilePath &filePath,
|
|
||||||
const Utils::FilePath::IterateDirCallback &callBack,
|
|
||||||
const Utils::FileFilter &filter) const override;
|
|
||||||
std::optional<QByteArray> fileContents(const Utils::FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const override;
|
|
||||||
bool writeFileContents(const Utils::FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const override;
|
|
||||||
Utils::FilePathInfo filePathInfo(const Utils::FilePath &filePath) const override;
|
|
||||||
QDateTime lastModified(const Utils::FilePath &filePath) const override;
|
|
||||||
qint64 fileSize(const Utils::FilePath &filePath) const override;
|
|
||||||
QFileDevice::Permissions permissions(const Utils::FilePath &filePath) const override;
|
|
||||||
bool setPermissions(const Utils::FilePath &filePath,
|
|
||||||
QFileDevice::Permissions permissions) const override;
|
|
||||||
bool ensureReachable(const Utils::FilePath &other) const override;
|
bool ensureReachable(const Utils::FilePath &other) const override;
|
||||||
|
|
||||||
Utils::Environment systemEnvironment() const override;
|
Utils::Environment systemEnvironment() const override;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
#include <projectexplorer/runcontrol.h>
|
#include <projectexplorer/runcontrol.h>
|
||||||
|
|
||||||
|
#include <utils/devicefileaccess.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/portlist.h>
|
#include <utils/portlist.h>
|
||||||
@@ -27,6 +28,8 @@ namespace ProjectExplorer {
|
|||||||
|
|
||||||
DesktopDevice::DesktopDevice()
|
DesktopDevice::DesktopDevice()
|
||||||
{
|
{
|
||||||
|
setFileAccess(DesktopDeviceFileAccess::instance());
|
||||||
|
|
||||||
setupId(IDevice::AutoDetected, DESKTOP_DEVICE_ID);
|
setupId(IDevice::AutoDetected, DESKTOP_DEVICE_ID);
|
||||||
setType(DESKTOP_DEVICE_TYPE);
|
setType(DESKTOP_DEVICE_TYPE);
|
||||||
setDefaultDisplayName(tr("Local PC"));
|
setDefaultDisplayName(tr("Local PC"));
|
||||||
@@ -136,33 +139,6 @@ bool DesktopDevice::handlesFile(const FilePath &filePath) const
|
|||||||
return !filePath.needsDevice();
|
return !filePath.needsDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopDevice::iterateDirectory(
|
|
||||||
const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
|
||||||
const FileFilter &filter) const
|
|
||||||
{
|
|
||||||
QTC_CHECK(!filePath.needsDevice());
|
|
||||||
filePath.iterateDirectory(callBack, filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 DesktopDevice::fileSize(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
|
||||||
return filePath.fileSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
QFile::Permissions DesktopDevice::permissions(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
return filePath.permissions();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::setPermissions(const FilePath &filePath, QFile::Permissions permissions) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
return filePath.setPermissions(permissions);
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath DesktopDevice::mapToGlobalPath(const Utils::FilePath &pathOnDevice) const
|
FilePath DesktopDevice::mapToGlobalPath(const Utils::FilePath &pathOnDevice) const
|
||||||
{
|
{
|
||||||
QTC_CHECK(!pathOnDevice.needsDevice());
|
QTC_CHECK(!pathOnDevice.needsDevice());
|
||||||
@@ -174,117 +150,4 @@ Environment DesktopDevice::systemEnvironment() const
|
|||||||
return Environment::systemEnvironment();
|
return Environment::systemEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopDevice::isExecutableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.isExecutableFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::isReadableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.isReadableFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::isWritableFile(const Utils::FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.isWritableFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::isReadableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.isReadableDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::isWritableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.isWritableDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::isFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.isFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::isDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.isDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::createDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.createDir();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::exists(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::ensureExistingFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.ensureExistingFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::removeFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.removeFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::removeRecursively(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.removeRecursively();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::copyFile(const FilePath &filePath, const FilePath &target) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return filePath.copyFile(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::renameFile(const FilePath &filePath, const FilePath &target) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
|
||||||
return filePath.renameFile(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
QDateTime DesktopDevice::lastModified(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
return filePath.lastModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath DesktopDevice::symLinkTarget(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
return filePath.symLinkTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<QByteArray> DesktopDevice::fileContents(const FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
return filePath.fileContents(limit, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DesktopDevice::writeFileContents(const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
return filePath.writeFileContents(data, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
|||||||
@@ -34,35 +34,6 @@ public:
|
|||||||
|
|
||||||
bool handlesFile(const Utils::FilePath &filePath) const override;
|
bool handlesFile(const Utils::FilePath &filePath) const override;
|
||||||
Utils::Environment systemEnvironment() const override;
|
Utils::Environment systemEnvironment() const override;
|
||||||
bool isExecutableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isReadableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isWritableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isReadableDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isWritableDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool ensureExistingFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool createDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool exists(const Utils::FilePath &filePath) const override;
|
|
||||||
bool removeFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool removeRecursively(const Utils::FilePath &filePath) const override;
|
|
||||||
bool copyFile(const Utils::FilePath &filePath, const Utils::FilePath &target) const override;
|
|
||||||
bool renameFile(const Utils::FilePath &filePath, const Utils::FilePath &target) const override;
|
|
||||||
QDateTime lastModified(const Utils::FilePath &filePath) const override;
|
|
||||||
Utils::FilePath symLinkTarget(const Utils::FilePath &filePath) const override;
|
|
||||||
void iterateDirectory(
|
|
||||||
const Utils::FilePath &filePath,
|
|
||||||
const Utils::FilePath::IterateDirCallback &callBack,
|
|
||||||
const Utils::FileFilter &filter) const override;
|
|
||||||
std::optional<QByteArray> fileContents(const Utils::FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const override;
|
|
||||||
bool writeFileContents(const Utils::FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const override;
|
|
||||||
qint64 fileSize(const Utils::FilePath &filePath) const override;
|
|
||||||
QFile::Permissions permissions(const Utils::FilePath &filePath) const override;
|
|
||||||
bool setPermissions(const Utils::FilePath &filePath, QFile::Permissions) const override;
|
|
||||||
Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const override;
|
Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
|
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/devicefileaccess.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/fsengine/fsengine.h>
|
#include <utils/fsengine/fsengine.h>
|
||||||
@@ -405,30 +407,6 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
|
|||||||
|
|
||||||
DeviceFileHooks &deviceHooks = DeviceFileHooks::instance();
|
DeviceFileHooks &deviceHooks = DeviceFileHooks::instance();
|
||||||
|
|
||||||
deviceHooks.isExecutableFile = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->isExecutableFile(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.isReadableFile = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->isReadableFile(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.isReadableDir = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->isReadableDirectory(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.isWritableDir = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->isWritableDirectory(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.isSameDevice = [](const FilePath &left, const FilePath &right) {
|
deviceHooks.isSameDevice = [](const FilePath &left, const FilePath &right) {
|
||||||
auto leftDevice = DeviceManager::deviceForPath(left);
|
auto leftDevice = DeviceManager::deviceForPath(left);
|
||||||
auto rightDevice = DeviceManager::deviceForPath(right);
|
auto rightDevice = DeviceManager::deviceForPath(right);
|
||||||
@@ -436,150 +414,12 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
|
|||||||
return leftDevice == rightDevice;
|
return leftDevice == rightDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
deviceHooks.isWritableFile = [](const FilePath &filePath) {
|
deviceHooks.fileAccess = [](const FilePath &filePath) -> DeviceFileAccess * {
|
||||||
|
if (!filePath.needsDevice())
|
||||||
|
return DesktopDeviceFileAccess::instance();
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
auto device = DeviceManager::deviceForPath(filePath);
|
||||||
QTC_ASSERT(device, return false);
|
QTC_ASSERT(device, return nullptr);
|
||||||
return device->isWritableFile(filePath);
|
return device->fileAccess();
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.isFile = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->isFile(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.isDir = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->isDirectory(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.ensureWritableDir = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->ensureWritableDirectory(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.ensureExistingFile = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->ensureExistingFile(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.createDir = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->createDirectory(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.exists = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->exists(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.removeFile = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->removeFile(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.removeRecursively = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->removeRecursively(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.copyFile = [](const FilePath &filePath, const FilePath &target) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->copyFile(filePath, target);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.renameFile = [](const FilePath &filePath, const FilePath &target) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->renameFile(filePath, target);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.searchInPath = [](const FilePath &filePath, const FilePaths &dirs) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return FilePath{});
|
|
||||||
return device->searchExecutable(filePath.path(), dirs);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.symLinkTarget = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return FilePath{});
|
|
||||||
return device->symLinkTarget(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.mapToDevicePath = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return QString{});
|
|
||||||
return device->mapToDevicePath(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.iterateDirectory = [](const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
|
||||||
const FileFilter &filter) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return );
|
|
||||||
device->iterateDirectory(filePath, callBack, filter);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.fileContents =
|
|
||||||
[](const FilePath &filePath, qint64 maxSize, qint64 offset) -> std::optional<QByteArray> {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return {});
|
|
||||||
return device->fileContents(filePath, maxSize, offset);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.asyncFileContents = [](const Continuation<std::optional<QByteArray>> &cont,
|
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 maxSize,
|
|
||||||
qint64 offset) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return);
|
|
||||||
device->asyncFileContents(cont, filePath, maxSize, offset);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.writeFileContents = [](const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->writeFileContents(filePath, data, offset);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.filePathInfo = [](const FilePath &filePath) -> FilePathInfo {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return {});
|
|
||||||
return device->filePathInfo(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.lastModified = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return QDateTime());
|
|
||||||
return device->lastModified(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.permissions = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return QFile::Permissions());
|
|
||||||
return device->permissions(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.setPermissions = [](const FilePath &filePath, QFile::Permissions permissions) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return false);
|
|
||||||
return device->setPermissions(filePath, permissions);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.osType = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return OsTypeOther);
|
|
||||||
return device->osType();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
deviceHooks.environment = [](const FilePath &filePath) {
|
deviceHooks.environment = [](const FilePath &filePath) {
|
||||||
@@ -588,18 +428,6 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
|
|||||||
return device->systemEnvironment();
|
return device->systemEnvironment();
|
||||||
};
|
};
|
||||||
|
|
||||||
deviceHooks.fileSize = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return qint64(-1));
|
|
||||||
return device->fileSize(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.bytesAvailable = [](const FilePath &filePath) {
|
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
|
||||||
QTC_ASSERT(device, return qint64(-1));
|
|
||||||
return device->bytesAvailable(filePath);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.deviceDisplayName = [](const FilePath &filePath) {
|
deviceHooks.deviceDisplayName = [](const FilePath &filePath) {
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
auto device = DeviceManager::deviceForPath(filePath);
|
||||||
QTC_ASSERT(device, return QString());
|
QTC_ASSERT(device, return QString());
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
|
|
||||||
|
#include <utils/devicefileaccess.h>
|
||||||
#include <utils/displayname.h>
|
#include <utils/displayname.h>
|
||||||
#include <utils/icon.h>
|
#include <utils/icon.h>
|
||||||
#include <utils/portlist.h>
|
#include <utils/portlist.h>
|
||||||
@@ -130,6 +131,7 @@ public:
|
|||||||
IDevice::DeviceState deviceState = IDevice::DeviceStateUnknown;
|
IDevice::DeviceState deviceState = IDevice::DeviceStateUnknown;
|
||||||
IDevice::MachineType machineType = IDevice::Hardware;
|
IDevice::MachineType machineType = IDevice::Hardware;
|
||||||
OsType osType = OsTypeOther;
|
OsType osType = OsTypeOther;
|
||||||
|
DeviceFileAccess *fileAccess = nullptr;
|
||||||
int version = 0; // This is used by devices that have been added by the SDK.
|
int version = 0; // This is used by devices that have been added by the SDK.
|
||||||
|
|
||||||
QReadWriteLock lock; // Currently used to protect sshParameters only
|
QReadWriteLock lock; // Currently used to protect sshParameters only
|
||||||
@@ -153,6 +155,8 @@ IDevice::IDevice() : d(new Internal::IDevicePrivate)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IDevice::~IDevice() = default;
|
||||||
|
|
||||||
void IDevice::setOpenTerminal(const IDevice::OpenTerminal &openTerminal)
|
void IDevice::setOpenTerminal(const IDevice::OpenTerminal &openTerminal)
|
||||||
{
|
{
|
||||||
d->openTerminal = openTerminal;
|
d->openTerminal = openTerminal;
|
||||||
@@ -191,6 +195,11 @@ bool IDevice::isAnyUnixDevice() const
|
|||||||
return d->osType == OsTypeLinux || d->osType == OsTypeMac || d->osType == OsTypeOtherUnix;
|
return d->osType == OsTypeLinux || d->osType == OsTypeMac || d->osType == OsTypeOtherUnix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeviceFileAccess *IDevice::fileAccess() const
|
||||||
|
{
|
||||||
|
return d->fileAccess;
|
||||||
|
}
|
||||||
|
|
||||||
FilePath IDevice::mapToGlobalPath(const FilePath &pathOnDevice) const
|
FilePath IDevice::mapToGlobalPath(const FilePath &pathOnDevice) const
|
||||||
{
|
{
|
||||||
if (pathOnDevice.needsDevice()) {
|
if (pathOnDevice.needsDevice()) {
|
||||||
@@ -219,113 +228,6 @@ bool IDevice::handlesFile(const FilePath &filePath) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IDevice::isExecutableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::isReadableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::isWritableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::isReadableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::isWritableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::isFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::isDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::ensureWritableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
if (isWritableDirectory(filePath))
|
|
||||||
return true;
|
|
||||||
return createDirectory(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::ensureExistingFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::createDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::exists(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::removeFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::removeRecursively(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::copyFile(const FilePath &filePath, const FilePath &target) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
Q_UNUSED(target);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::renameFile(const FilePath &filePath, const FilePath &target) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
Q_UNUSED(target);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath IDevice::searchExecutableInPath(const QString &fileName) const
|
FilePath IDevice::searchExecutableInPath(const QString &fileName) const
|
||||||
{
|
{
|
||||||
FilePaths paths;
|
FilePaths paths;
|
||||||
@@ -341,108 +243,13 @@ FilePath IDevice::searchExecutable(const QString &fileName, const FilePaths &dir
|
|||||||
dir = mapToGlobalPath(dir);
|
dir = mapToGlobalPath(dir);
|
||||||
QTC_CHECK(handlesFile(dir));
|
QTC_CHECK(handlesFile(dir));
|
||||||
const FilePath candidate = dir / fileName;
|
const FilePath candidate = dir / fileName;
|
||||||
if (isExecutableFile(candidate))
|
if (candidate.isExecutableFile())
|
||||||
return candidate;
|
return candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath IDevice::symLinkTarget(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDevice::iterateDirectory(const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
|
||||||
const FileFilter &filter) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
Q_UNUSED(callBack);
|
|
||||||
Q_UNUSED(filter);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<QByteArray> IDevice::fileContents(const FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
Q_UNUSED(limit);
|
|
||||||
Q_UNUSED(offset);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDevice::asyncFileContents(const Continuation<std::optional<QByteArray>> &cont,
|
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
cont(fileContents(filePath, limit, offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::writeFileContents(const FilePath &filePath, const QByteArray &data, qint64 offset) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
Q_UNUSED(data);
|
|
||||||
Q_UNUSED(offset);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePathInfo IDevice::filePathInfo(const Utils::FilePath &filePath) const
|
|
||||||
{
|
|
||||||
bool exists = filePath.exists();
|
|
||||||
if (!exists)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
FilePathInfo result {
|
|
||||||
filePath.fileSize(),
|
|
||||||
{FilePathInfo::ExistsFlag},
|
|
||||||
filePath.lastModified(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (filePath.isDir())
|
|
||||||
result.fileFlags |= FilePathInfo::DirectoryType;
|
|
||||||
if (filePath.isFile())
|
|
||||||
result.fileFlags |= FilePathInfo::FileType;
|
|
||||||
if (filePath.isRootPath())
|
|
||||||
result.fileFlags |= FilePathInfo::RootFlag;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDevice::asyncWriteFileContents(const Continuation<bool> &cont,
|
|
||||||
const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
cont(writeFileContents(filePath, data, offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
QDateTime IDevice::lastModified(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileDevice::Permissions IDevice::permissions(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IDevice::setPermissions(const FilePath &filePath, QFile::Permissions) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath);
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessInterface *IDevice::createProcessInterface() const
|
ProcessInterface *IDevice::createProcessInterface() const
|
||||||
{
|
{
|
||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
@@ -463,22 +270,6 @@ Environment IDevice::systemEnvironment() const
|
|||||||
return Environment::systemEnvironment();
|
return Environment::systemEnvironment();
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 IDevice::fileSize(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath)
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 IDevice::bytesAvailable(const Utils::FilePath &filePath) const
|
|
||||||
{
|
|
||||||
Q_UNUSED(filePath)
|
|
||||||
QTC_CHECK(false);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
IDevice::~IDevice() = default;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Specifies a free-text name for the device to be displayed in GUI elements.
|
Specifies a free-text name for the device to be displayed in GUI elements.
|
||||||
*/
|
*/
|
||||||
@@ -513,6 +304,11 @@ void IDevice::setOsType(OsType osType)
|
|||||||
d->osType = osType;
|
d->osType = osType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IDevice::setFileAccess(DeviceFileAccess *fileAccess)
|
||||||
|
{
|
||||||
|
d->fileAccess = fileAccess;
|
||||||
|
}
|
||||||
|
|
||||||
IDevice::DeviceInfo IDevice::deviceInformation() const
|
IDevice::DeviceInfo IDevice::deviceInformation() const
|
||||||
{
|
{
|
||||||
const QString key = QCoreApplication::translate("ProjectExplorer::IDevice", "Device");
|
const QString key = QCoreApplication::translate("ProjectExplorer::IDevice", "Device");
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
class CommandLine;
|
class CommandLine;
|
||||||
|
class DeviceFileAccess;
|
||||||
class Environment;
|
class Environment;
|
||||||
class Icon;
|
class Icon;
|
||||||
class PortList;
|
class PortList;
|
||||||
@@ -214,62 +215,23 @@ public:
|
|||||||
bool isMacDevice() const { return osType() == Utils::OsTypeMac; }
|
bool isMacDevice() const { return osType() == Utils::OsTypeMac; }
|
||||||
bool isAnyUnixDevice() const;
|
bool isAnyUnixDevice() const;
|
||||||
|
|
||||||
|
Utils::DeviceFileAccess *fileAccess() const;
|
||||||
|
virtual bool handlesFile(const Utils::FilePath &filePath) const;
|
||||||
|
|
||||||
virtual Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const;
|
virtual Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const;
|
||||||
virtual QString mapToDevicePath(const Utils::FilePath &globalPath) const;
|
virtual QString mapToDevicePath(const Utils::FilePath &globalPath) const;
|
||||||
|
|
||||||
virtual bool handlesFile(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool isExecutableFile(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool isReadableFile(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool isWritableFile(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool isReadableDirectory(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool isWritableDirectory(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool isFile(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool isDirectory(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool ensureWritableDirectory(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool ensureExistingFile(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool createDirectory(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool exists(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool removeFile(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool removeRecursively(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool copyFile(const Utils::FilePath &filePath, const Utils::FilePath &target) const;
|
|
||||||
virtual bool renameFile(const Utils::FilePath &filePath, const Utils::FilePath &target) const;
|
|
||||||
virtual Utils::FilePath searchExecutableInPath(const QString &fileName) const;
|
virtual Utils::FilePath searchExecutableInPath(const QString &fileName) const;
|
||||||
virtual Utils::FilePath searchExecutable(const QString &fileName,
|
virtual Utils::FilePath searchExecutable(const QString &fileName,
|
||||||
const Utils::FilePaths &dirs) const;
|
const Utils::FilePaths &dirs) const;
|
||||||
virtual Utils::FilePath symLinkTarget(const Utils::FilePath &filePath) const;
|
|
||||||
virtual void iterateDirectory(
|
|
||||||
const Utils::FilePath &filePath,
|
|
||||||
const Utils::FilePath::IterateDirCallback &callBack,
|
|
||||||
const Utils::FileFilter &filter) const;
|
|
||||||
|
|
||||||
virtual std::optional<QByteArray> fileContents(const Utils::FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const;
|
|
||||||
virtual bool writeFileContents(const Utils::FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const;
|
|
||||||
virtual Utils::FilePathInfo filePathInfo(const Utils::FilePath &filePath) const;
|
|
||||||
virtual QDateTime lastModified(const Utils::FilePath &filePath) const;
|
|
||||||
virtual QFile::Permissions permissions(const Utils::FilePath &filePath) const;
|
|
||||||
virtual bool setPermissions(const Utils::FilePath &filePath, QFile::Permissions) const;
|
|
||||||
virtual Utils::ProcessInterface *createProcessInterface() const;
|
virtual Utils::ProcessInterface *createProcessInterface() const;
|
||||||
virtual FileTransferInterface *createFileTransferInterface(
|
virtual FileTransferInterface *createFileTransferInterface(
|
||||||
const FileTransferSetupData &setup) const;
|
const FileTransferSetupData &setup) const;
|
||||||
virtual Utils::Environment systemEnvironment() const;
|
virtual Utils::Environment systemEnvironment() const;
|
||||||
virtual qint64 fileSize(const Utils::FilePath &filePath) const;
|
|
||||||
virtual qint64 bytesAvailable(const Utils::FilePath &filePath) const;
|
|
||||||
|
|
||||||
virtual void aboutToBeRemoved() const {}
|
virtual void aboutToBeRemoved() const {}
|
||||||
|
|
||||||
virtual void asyncFileContents(const Continuation<std::optional<QByteArray>> &cont,
|
|
||||||
const Utils::FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const;
|
|
||||||
virtual void asyncWriteFileContents(const Continuation<bool> &cont,
|
|
||||||
const Utils::FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const;
|
|
||||||
|
|
||||||
virtual bool ensureReachable(const Utils::FilePath &other) const;
|
virtual bool ensureReachable(const Utils::FilePath &other) const;
|
||||||
|
|
||||||
virtual bool prepareForBuild(const Target *target);
|
virtual bool prepareForBuild(const Target *target);
|
||||||
@@ -284,6 +246,7 @@ protected:
|
|||||||
void setOpenTerminal(const OpenTerminal &openTerminal);
|
void setOpenTerminal(const OpenTerminal &openTerminal);
|
||||||
void setDisplayType(const QString &type);
|
void setDisplayType(const QString &type);
|
||||||
void setOsType(Utils::OsType osType);
|
void setOsType(Utils::OsType osType);
|
||||||
|
void setFileAccess(Utils::DeviceFileAccess *fileAccess);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IDevice(const IDevice &) = delete;
|
IDevice(const IDevice &) = delete;
|
||||||
|
|||||||
@@ -1118,8 +1118,7 @@ static FilePaths findCompilerCandidates(const ToolchainDetector &detector,
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
const FilePath globalDir = device->mapToGlobalPath(deviceDir);
|
const FilePath globalDir = device->mapToGlobalPath(deviceDir);
|
||||||
device->iterateDirectory(globalDir, callBack,
|
globalDir.iterateDirectory(callBack, {nameFilters, QDir::Files | QDir::Executable});
|
||||||
{nameFilters, QDir::Files | QDir::Executable});
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// The normal, local host case.
|
// The normal, local host case.
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <projectexplorer/runcontrol.h>
|
#include <projectexplorer/runcontrol.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/devicefileaccess.h>
|
||||||
#include <utils/deviceshell.h>
|
#include <utils/deviceshell.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
@@ -349,6 +350,21 @@ private:
|
|||||||
// LinuxDevicePrivate
|
// LinuxDevicePrivate
|
||||||
|
|
||||||
class ShellThreadHandler;
|
class ShellThreadHandler;
|
||||||
|
class LinuxDevicePrivate;
|
||||||
|
|
||||||
|
class LinuxDeviceFileAccess : public UnixDeviceFileAccess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LinuxDeviceFileAccess(LinuxDevicePrivate *dev)
|
||||||
|
: m_dev(dev)
|
||||||
|
{}
|
||||||
|
|
||||||
|
RunResult runInShell(const QString &executable,
|
||||||
|
const QStringList &arguments,
|
||||||
|
const QByteArray &stdInData) const override;
|
||||||
|
|
||||||
|
LinuxDevicePrivate *m_dev;
|
||||||
|
};
|
||||||
|
|
||||||
class LinuxDevicePrivate
|
class LinuxDevicePrivate
|
||||||
{
|
{
|
||||||
@@ -358,9 +374,6 @@ public:
|
|||||||
|
|
||||||
bool setupShell();
|
bool setupShell();
|
||||||
RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {});
|
RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {});
|
||||||
bool runInShellSuccess(const CommandLine &cmd, const QByteArray &stdInData = {}) {
|
|
||||||
return runInShell(cmd, stdInData).exitCode == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void attachToSharedConnection(SshConnectionHandle *connectionHandle,
|
void attachToSharedConnection(SshConnectionHandle *connectionHandle,
|
||||||
const SshParameters &sshParameters);
|
const SshParameters &sshParameters);
|
||||||
@@ -370,9 +383,16 @@ public:
|
|||||||
ShellThreadHandler *m_handler = nullptr;
|
ShellThreadHandler *m_handler = nullptr;
|
||||||
mutable QMutex m_shellMutex;
|
mutable QMutex m_shellMutex;
|
||||||
QList<QtcProcess *> m_terminals;
|
QList<QtcProcess *> m_terminals;
|
||||||
bool m_useFind = true;
|
LinuxDeviceFileAccess m_fileAccess{this};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RunResult LinuxDeviceFileAccess::runInShell(const QString &executable,
|
||||||
|
const QStringList &arguments,
|
||||||
|
const QByteArray &stdInData) const
|
||||||
|
{
|
||||||
|
return m_dev->runInShell({FilePath::fromString(executable), arguments}, stdInData);
|
||||||
|
}
|
||||||
|
|
||||||
// SshProcessImpl
|
// SshProcessImpl
|
||||||
|
|
||||||
class SshProcessInterfacePrivate : public QObject
|
class SshProcessInterfacePrivate : public QObject
|
||||||
@@ -465,7 +485,7 @@ qint64 SshProcessInterface::processId() const
|
|||||||
|
|
||||||
bool SshProcessInterface::runInShell(const CommandLine &command, const QByteArray &data)
|
bool SshProcessInterface::runInShell(const CommandLine &command, const QByteArray &data)
|
||||||
{
|
{
|
||||||
return d->m_devicePrivate->runInShellSuccess(command, data);
|
return d->m_devicePrivate->runInShell(command, data).exitCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SshProcessInterface::start()
|
void SshProcessInterface::start()
|
||||||
@@ -904,6 +924,7 @@ private:
|
|||||||
LinuxDevice::LinuxDevice()
|
LinuxDevice::LinuxDevice()
|
||||||
: d(new LinuxDevicePrivate(this))
|
: d(new LinuxDevicePrivate(this))
|
||||||
{
|
{
|
||||||
|
setFileAccess(&d->m_fileAccess);
|
||||||
setDisplayType(Tr::tr("Remote Linux"));
|
setDisplayType(Tr::tr("Remote Linux"));
|
||||||
setDefaultDisplayName(Tr::tr("Remote Linux Device"));
|
setDefaultDisplayName(Tr::tr("Remote Linux Device"));
|
||||||
setOsType(OsTypeLinux);
|
setOsType(OsTypeLinux);
|
||||||
@@ -1121,223 +1142,6 @@ void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectio
|
|||||||
emit connectionHandle->connected(socketFilePath);
|
emit connectionHandle->connected(socketFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevice::isExecutableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-x", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::isReadableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-r", path, "-a", "-f", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::isWritableFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-w", path, "-a", "-f", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::isReadableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-r", path, "-a", "-d", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::isWritableDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-w", path, "-a", "-d", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::isFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-f", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::isDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-d", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::createDirectory(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"mkdir", {"-p", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::exists(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
DEBUG("filepath " << filePath.path());
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"test", {"-e", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::ensureExistingFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const QString path = filePath.path();
|
|
||||||
return d->runInShellSuccess({"touch", {path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::removeFile(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
return d->runInShellSuccess({"rm", {filePath.path()}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::removeRecursively(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
QTC_ASSERT(filePath.path().startsWith('/'), return false);
|
|
||||||
|
|
||||||
const QString path = filePath.cleanPath().path();
|
|
||||||
// We are expecting this only to be called in a context of build directories or similar.
|
|
||||||
// Chicken out in some cases that _might_ be user code errors.
|
|
||||||
QTC_ASSERT(path.startsWith('/'), return false);
|
|
||||||
const int levelsNeeded = path.startsWith("/home/") ? 3 : 2;
|
|
||||||
QTC_ASSERT(path.count('/') >= levelsNeeded, return false);
|
|
||||||
|
|
||||||
return d->runInShellSuccess({"rm", {"-rf", "--", path}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::copyFile(const FilePath &filePath, const FilePath &target) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
|
||||||
return d->runInShellSuccess({"cp", {filePath.path(), target.path()}});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::renameFile(const FilePath &filePath, const FilePath &target) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
QTC_ASSERT(handlesFile(target), return false);
|
|
||||||
return d->runInShellSuccess({"mv", {filePath.path(), target.path()}});
|
|
||||||
}
|
|
||||||
|
|
||||||
QDateTime LinuxDevice::lastModified(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%Y", filePath.path()}});
|
|
||||||
const qint64 secs = result.stdOut.toLongLong();
|
|
||||||
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath LinuxDevice::symLinkTarget(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
const RunResult result = d->runInShell({"readlink", {"-n", "-e", filePath.path()}});
|
|
||||||
return result.stdOut.isEmpty() ? FilePath()
|
|
||||||
: filePath.withNewPath(QString::fromUtf8(result.stdOut));
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 LinuxDevice::fileSize(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
|
||||||
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%s", filePath.path()}});
|
|
||||||
return result.stdOut.toLongLong();
|
|
||||||
}
|
|
||||||
|
|
||||||
qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
|
||||||
CommandLine cmd("df", {"-k"});
|
|
||||||
cmd.addArg(filePath.path());
|
|
||||||
const RunResult result = d->runInShell(cmd);
|
|
||||||
return FileUtils::bytesAvailableFromDFOutput(result.stdOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
const RunResult result = d->runInShell({"stat", {"-L", "-c", "%a", filePath.path()}});
|
|
||||||
const uint bits = result.stdOut.toUInt(nullptr, 8);
|
|
||||||
QFileDevice::Permissions perm = {};
|
|
||||||
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
|
||||||
BIT(0, ExeOther);
|
|
||||||
BIT(1, WriteOther);
|
|
||||||
BIT(2, ReadOther);
|
|
||||||
BIT(3, ExeGroup);
|
|
||||||
BIT(4, WriteGroup);
|
|
||||||
BIT(5, ReadGroup);
|
|
||||||
BIT(6, ExeUser);
|
|
||||||
BIT(7, WriteUser);
|
|
||||||
BIT(8, ReadUser);
|
|
||||||
#undef BIT
|
|
||||||
return perm;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::setPermissions(const FilePath &filePath, QFileDevice::Permissions permissions) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return false);
|
|
||||||
const int flags = int(permissions);
|
|
||||||
return d->runInShellSuccess({"chmod", {QString::number(flags, 16), filePath.path()}});
|
|
||||||
}
|
|
||||||
|
|
||||||
void LinuxDevice::iterateDirectory(const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
|
||||||
const FileFilter &filter) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return);
|
|
||||||
auto runInShell = [this](const CommandLine &cmd) { return d->runInShell(cmd); };
|
|
||||||
FileUtils::iterateUnixDirectory(filePath, filter, &d->m_useFind, runInShell, callBack);
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePathInfo LinuxDevice::filePathInfo(const FilePath &filePath) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
const RunResult stat = d->runInShell({"stat", {"-L", "-c", "%f %Y %s", filePath.path()}});
|
|
||||||
return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<QByteArray> LinuxDevice::fileContents(const FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
QString args = "if=" + filePath.path() + " status=none";
|
|
||||||
if (limit > 0 || offset > 0) {
|
|
||||||
const qint64 gcd = std::gcd(limit, offset);
|
|
||||||
args += QString(" bs=%1 count=%2 seek=%3").arg(gcd).arg(limit / gcd).arg(offset / gcd);
|
|
||||||
}
|
|
||||||
CommandLine cmd(FilePath::fromString("dd"), args, CommandLine::Raw);
|
|
||||||
|
|
||||||
const RunResult result = d->runInShell(cmd);
|
|
||||||
if (result.exitCode != 0) {
|
|
||||||
DEBUG("fileContents failed");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(result.stdOut << QByteArray::fromHex(result.stdOut));
|
|
||||||
return result.stdOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinuxDevice::writeFileContents(const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
|
||||||
CommandLine cmd({"dd", {"of=" + filePath.path()}});
|
|
||||||
if (offset != 0) {
|
|
||||||
cmd.addArg("bs=1");
|
|
||||||
cmd.addArg(QString("seek=%1").arg(offset));
|
|
||||||
}
|
|
||||||
return d->runInShellSuccess(cmd, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FilePaths dirsToCreate(const FilesToTransfer &files)
|
static FilePaths dirsToCreate(const FilesToTransfer &files)
|
||||||
{
|
{
|
||||||
FilePaths dirs;
|
FilePaths dirs;
|
||||||
|
|||||||
@@ -37,40 +37,11 @@ public:
|
|||||||
Utils::FilePath rootPath() const override;
|
Utils::FilePath rootPath() const override;
|
||||||
|
|
||||||
bool handlesFile(const Utils::FilePath &filePath) const override;
|
bool handlesFile(const Utils::FilePath &filePath) const override;
|
||||||
bool isExecutableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isReadableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isWritableFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isReadableDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isWritableDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool isDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool createDirectory(const Utils::FilePath &filePath) const override;
|
|
||||||
bool exists(const Utils::FilePath &filePath) const override;
|
|
||||||
bool ensureExistingFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool removeFile(const Utils::FilePath &filePath) const override;
|
|
||||||
bool removeRecursively(const Utils::FilePath &filePath) const override;
|
|
||||||
bool copyFile(const Utils::FilePath &filePath, const Utils::FilePath &target) const override;
|
|
||||||
bool renameFile(const Utils::FilePath &filePath, const Utils::FilePath &target) const override;
|
|
||||||
Utils::FilePath symLinkTarget(const Utils::FilePath &filePath) const override;
|
|
||||||
void iterateDirectory(const Utils::FilePath &filePath,
|
|
||||||
const Utils::FilePath::IterateDirCallback &callBack,
|
|
||||||
const Utils::FileFilter &filter) const override;
|
|
||||||
std::optional<QByteArray> fileContents(const Utils::FilePath &filePath,
|
|
||||||
qint64 limit,
|
|
||||||
qint64 offset) const override;
|
|
||||||
bool writeFileContents(const Utils::FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) const override;
|
|
||||||
Utils::FilePathInfo filePathInfo(const Utils::FilePath &filePath) const override;
|
|
||||||
QDateTime lastModified(const Utils::FilePath &filePath) const override;
|
|
||||||
Utils::ProcessInterface *createProcessInterface() const override;
|
Utils::ProcessInterface *createProcessInterface() const override;
|
||||||
ProjectExplorer::FileTransferInterface *createFileTransferInterface(
|
ProjectExplorer::FileTransferInterface *createFileTransferInterface(
|
||||||
const ProjectExplorer::FileTransferSetupData &setup) const override;
|
const ProjectExplorer::FileTransferSetupData &setup) const override;
|
||||||
Utils::Environment systemEnvironment() const override;
|
Utils::Environment systemEnvironment() const override;
|
||||||
qint64 fileSize(const Utils::FilePath &filePath) const override;
|
|
||||||
qint64 bytesAvailable(const Utils::FilePath &filePath) const override;
|
|
||||||
QFileDevice::Permissions permissions(const Utils::FilePath &filePath) const override;
|
|
||||||
bool setPermissions(const Utils::FilePath &filePath, QFileDevice::Permissions permissions) const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LinuxDevice();
|
LinuxDevice();
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ extend_qtc_library(sdktoolLib
|
|||||||
PUBLIC_DEFINES UTILS_STATIC_LIBRARY
|
PUBLIC_DEFINES UTILS_STATIC_LIBRARY
|
||||||
SOURCES
|
SOURCES
|
||||||
commandline.cpp commandline.h
|
commandline.cpp commandline.h
|
||||||
|
devicefileaccess.cpp devicefileaccess.h
|
||||||
environment.cpp environment.h
|
environment.cpp environment.h
|
||||||
filepath.cpp filepath.h
|
filepath.cpp filepath.h
|
||||||
fileutils.cpp fileutils.h
|
fileutils.cpp fileutils.h
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ QtcLibrary {
|
|||||||
prefix: libsDir + "/utils/"
|
prefix: libsDir + "/utils/"
|
||||||
files: [
|
files: [
|
||||||
"commandline.cpp", "commandline.h",
|
"commandline.cpp", "commandline.h",
|
||||||
|
"devicefileaccess.cpp", "devicefileaccess.h",
|
||||||
"environment.cpp", "environment.h",
|
"environment.cpp", "environment.h",
|
||||||
"filepath.cpp", "filepath.h",
|
"filepath.cpp", "filepath.h",
|
||||||
"fileutils.cpp", "fileutils.h",
|
"fileutils.cpp", "fileutils.h",
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include <utils/filepath.h>
|
#include <utils/filepath.h>
|
||||||
#include <utils/fileutils.h>
|
|
||||||
#include <utils/fsengine/fsengine.h>
|
#include <utils/fsengine/fsengine.h>
|
||||||
|
#include <utils/environment.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
@@ -58,119 +58,6 @@ void tst_fsengine::initTestCase()
|
|||||||
if (HostOsInfo::isWindowsHost())
|
if (HostOsInfo::isWindowsHost())
|
||||||
QSKIP("The fsengine tests are not supported on Windows.");
|
QSKIP("The fsengine tests are not supported on Windows.");
|
||||||
|
|
||||||
DeviceFileHooks &deviceHooks = DeviceFileHooks::instance();
|
|
||||||
|
|
||||||
deviceHooks.fileContents =
|
|
||||||
[](const FilePath &path, qint64 maxSize, qint64 offset) -> std::optional<QByteArray> {
|
|
||||||
return FilePath::fromString(path.path()).fileContents(maxSize, offset);
|
|
||||||
};
|
|
||||||
|
|
||||||
deviceHooks.isExecutableFile = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).isExecutableFile();
|
|
||||||
};
|
|
||||||
deviceHooks.isReadableFile = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).isReadableFile();
|
|
||||||
};
|
|
||||||
deviceHooks.isReadableDir = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).isReadableDir();
|
|
||||||
};
|
|
||||||
deviceHooks.isWritableDir = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).isWritableDir();
|
|
||||||
};
|
|
||||||
deviceHooks.isWritableFile = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).isWritableFile();
|
|
||||||
};
|
|
||||||
deviceHooks.isFile = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).isFile();
|
|
||||||
};
|
|
||||||
deviceHooks.isDir = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).isDir();
|
|
||||||
};
|
|
||||||
deviceHooks.ensureWritableDir = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).ensureWritableDir();
|
|
||||||
};
|
|
||||||
deviceHooks.ensureExistingFile = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).ensureExistingFile();
|
|
||||||
};
|
|
||||||
deviceHooks.createDir = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).createDir();
|
|
||||||
};
|
|
||||||
deviceHooks.exists = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).exists();
|
|
||||||
};
|
|
||||||
deviceHooks.removeFile = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).removeFile();
|
|
||||||
};
|
|
||||||
deviceHooks.removeRecursively = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).removeRecursively();
|
|
||||||
};
|
|
||||||
deviceHooks.copyFile = [](const FilePath &filePath, const FilePath &target) {
|
|
||||||
return FilePath::fromString(filePath.path()).copyFile(target);
|
|
||||||
};
|
|
||||||
deviceHooks.renameFile = [](const FilePath &filePath, const FilePath &target) {
|
|
||||||
return FilePath::fromString(filePath.path()).renameFile(target);
|
|
||||||
};
|
|
||||||
deviceHooks.searchInPath = [](const FilePath &filePath, const FilePaths &dirs) {
|
|
||||||
return FilePath::fromString(filePath.path()).searchInPath(dirs);
|
|
||||||
};
|
|
||||||
deviceHooks.symLinkTarget = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).symLinkTarget();
|
|
||||||
};
|
|
||||||
deviceHooks.iterateDirectory = [](const FilePath &filePath,
|
|
||||||
const FilePath::IterateDirCallback &callBack,
|
|
||||||
const FileFilter &filter) {
|
|
||||||
const FilePath fp = FilePath::fromString(filePath.path());
|
|
||||||
if (callBack.index() == 0) {
|
|
||||||
fp.iterateDirectory(
|
|
||||||
[&filePath, cb = std::get<0>(callBack)](const FilePath &path) {
|
|
||||||
return cb(path.onDevice(filePath));
|
|
||||||
},
|
|
||||||
filter);
|
|
||||||
} else {
|
|
||||||
fp.iterateDirectory(
|
|
||||||
[&filePath, cb = std::get<1>(callBack)](const FilePath &path, const FilePathInfo &fpi) {
|
|
||||||
return cb(path.onDevice(filePath), fpi);
|
|
||||||
},
|
|
||||||
filter);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
deviceHooks.asyncFileContents = [](const Continuation<const std::optional<QByteArray> &> &cont,
|
|
||||||
const FilePath &filePath,
|
|
||||||
qint64 maxSize,
|
|
||||||
qint64 offset) {
|
|
||||||
return FilePath::fromString(filePath.path()).asyncFileContents(cont, maxSize, offset);
|
|
||||||
};
|
|
||||||
deviceHooks.writeFileContents = [](const FilePath &filePath,
|
|
||||||
const QByteArray &data,
|
|
||||||
qint64 offset) {
|
|
||||||
return FilePath::fromString(filePath.path()).writeFileContents(data, offset);
|
|
||||||
};
|
|
||||||
deviceHooks.lastModified = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).lastModified();
|
|
||||||
};
|
|
||||||
deviceHooks.permissions = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).permissions();
|
|
||||||
};
|
|
||||||
deviceHooks.setPermissions = [](const FilePath &filePath, QFile::Permissions permissions) {
|
|
||||||
return FilePath::fromString(filePath.path()).setPermissions(permissions);
|
|
||||||
};
|
|
||||||
deviceHooks.osType = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).osType();
|
|
||||||
};
|
|
||||||
// deviceHooks.environment = [](const FilePath &filePath) -> Environment {return {};};
|
|
||||||
deviceHooks.fileSize = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).fileSize();
|
|
||||||
};
|
|
||||||
deviceHooks.bytesAvailable = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).bytesAvailable();
|
|
||||||
};
|
|
||||||
deviceHooks.filePathInfo = [](const FilePath &filePath) {
|
|
||||||
return FilePath::fromString(filePath.path()).filePathInfo();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
deviceHooks.mapToDevicePath = [](const FilePath &filePath) { return filePath.path(); };
|
|
||||||
|
|
||||||
FSEngine::addDevice(FilePath::fromString("device://test"));
|
FSEngine::addDevice(FilePath::fromString("device://test"));
|
||||||
|
|
||||||
tempFolder = QDir::tempPath();
|
tempFolder = QDir::tempPath();
|
||||||
|
|||||||
Reference in New Issue
Block a user