forked from qt-creator/qt-creator
FilePath: Return optional bytearray from device hooks
For differentiating between "error" and "empty file". Change-Id: I1806bb7386f5e7db28489f9f7e685648bfc20110 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -534,7 +534,6 @@ std::optional<QByteArray> FilePath::fileContents(qint64 maxSize, qint64 offset)
|
|||||||
{
|
{
|
||||||
if (needsDevice()) {
|
if (needsDevice()) {
|
||||||
QTC_ASSERT(s_deviceHooks.fileContents, return {});
|
QTC_ASSERT(s_deviceHooks.fileContents, return {});
|
||||||
// TODO change hooks to return optional byte array
|
|
||||||
return s_deviceHooks.fileContents(*this, maxSize, offset);
|
return s_deviceHooks.fileContents(*this, maxSize, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ public:
|
|||||||
std::function<void(const FilePath &,
|
std::function<void(const FilePath &,
|
||||||
const std::function<bool(const FilePath &)> &, // Abort on 'false' return.
|
const std::function<bool(const FilePath &)> &, // Abort on 'false' return.
|
||||||
const FileFilter &)> iterateDirectory;
|
const FileFilter &)> iterateDirectory;
|
||||||
std::function<QByteArray(const FilePath &, qint64, qint64)> fileContents;
|
std::function<std::optional<QByteArray>(const FilePath &, qint64, qint64)> fileContents;
|
||||||
std::function<bool(const FilePath &, const QByteArray &)> writeFileContents;
|
std::function<bool(const FilePath &, const QByteArray &)> writeFileContents;
|
||||||
std::function<QDateTime(const FilePath &)> lastModified;
|
std::function<QDateTime(const FilePath &)> lastModified;
|
||||||
std::function<QFile::Permissions(const FilePath &)> permissions;
|
std::function<QFile::Permissions(const FilePath &)> permissions;
|
||||||
|
|||||||
@@ -958,7 +958,9 @@ void DockerDevice::iterateDirectory(const FilePath &filePath,
|
|||||||
FileUtils::iterateLsOutput(filePath, entries, filter, callBack);
|
FileUtils::iterateLsOutput(filePath, entries, filter, callBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray DockerDevice::fileContents(const FilePath &filePath, qint64 limit, qint64 offset) const
|
std::optional<QByteArray> DockerDevice::fileContents(const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
updateContainerAccess();
|
updateContainerAccess();
|
||||||
@@ -976,6 +978,8 @@ QByteArray DockerDevice::fileContents(const FilePath &filePath, qint64 limit, qi
|
|||||||
proc.start();
|
proc.start();
|
||||||
proc.waitForFinished();
|
proc.waitForFinished();
|
||||||
|
|
||||||
|
if (proc.result() != ProcessResult::FinishedWithSuccess)
|
||||||
|
return {};
|
||||||
QByteArray output = proc.readAllStandardOutput();
|
QByteArray output = proc.readAllStandardOutput();
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,9 @@ public:
|
|||||||
void iterateDirectory(const Utils::FilePath &filePath,
|
void iterateDirectory(const Utils::FilePath &filePath,
|
||||||
const std::function<bool(const Utils::FilePath &)> &callBack,
|
const std::function<bool(const Utils::FilePath &)> &callBack,
|
||||||
const Utils::FileFilter &filter) const override;
|
const Utils::FileFilter &filter) const override;
|
||||||
QByteArray fileContents(const Utils::FilePath &filePath, qint64 limit, qint64 offset) 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) const override;
|
bool writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const override;
|
||||||
QDateTime lastModified(const Utils::FilePath &filePath) const override;
|
QDateTime lastModified(const Utils::FilePath &filePath) const override;
|
||||||
qint64 fileSize(const Utils::FilePath &filePath) const override;
|
qint64 fileSize(const Utils::FilePath &filePath) const override;
|
||||||
|
|||||||
@@ -265,10 +265,12 @@ FilePath DesktopDevice::symLinkTarget(const FilePath &filePath) const
|
|||||||
return filePath.symLinkTarget();
|
return filePath.symLinkTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray DesktopDevice::fileContents(const FilePath &filePath, qint64 limit, qint64 offset) const
|
std::optional<QByteArray> DesktopDevice::fileContents(const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
return filePath.fileContents(limit, offset).value_or(QByteArray());
|
return filePath.fileContents(limit, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopDevice::writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const
|
bool DesktopDevice::writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ public:
|
|||||||
void iterateDirectory(const Utils::FilePath &filePath,
|
void iterateDirectory(const Utils::FilePath &filePath,
|
||||||
const std::function<bool(const Utils::FilePath &)> &callBack,
|
const std::function<bool(const Utils::FilePath &)> &callBack,
|
||||||
const Utils::FileFilter &filter) const override;
|
const Utils::FileFilter &filter) const override;
|
||||||
QByteArray fileContents(const Utils::FilePath &filePath, qint64 limit, qint64 offset) 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) const override;
|
bool writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const override;
|
||||||
qint64 fileSize(const Utils::FilePath &filePath) const override;
|
qint64 fileSize(const Utils::FilePath &filePath) const override;
|
||||||
QFile::Permissions permissions(const Utils::FilePath &filePath) const override;
|
QFile::Permissions permissions(const Utils::FilePath &filePath) const override;
|
||||||
|
|||||||
@@ -521,14 +521,17 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
|
|||||||
device->iterateDirectory(filePath, callBack, filter);
|
device->iterateDirectory(filePath, callBack, filter);
|
||||||
};
|
};
|
||||||
|
|
||||||
deviceHooks.fileContents = [](const FilePath &filePath, qint64 maxSize, qint64 offset) {
|
deviceHooks.fileContents =
|
||||||
|
[](const FilePath &filePath, qint64 maxSize, qint64 offset) -> std::optional<QByteArray> {
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
auto device = DeviceManager::deviceForPath(filePath);
|
||||||
QTC_ASSERT(device, return QByteArray());
|
QTC_ASSERT(device, return {});
|
||||||
return device->fileContents(filePath, maxSize, offset);
|
return device->fileContents(filePath, maxSize, offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
deviceHooks.asyncFileContents = [](const Continuation<QByteArray> &cont, const FilePath &filePath,
|
deviceHooks.asyncFileContents = [](const Continuation<std::optional<QByteArray>> &cont,
|
||||||
qint64 maxSize, qint64 offset) {
|
const FilePath &filePath,
|
||||||
|
qint64 maxSize,
|
||||||
|
qint64 offset) {
|
||||||
auto device = DeviceManager::deviceForPath(filePath);
|
auto device = DeviceManager::deviceForPath(filePath);
|
||||||
QTC_ASSERT(device, return);
|
QTC_ASSERT(device, return);
|
||||||
device->asyncFileContents(cont, filePath, maxSize, offset);
|
device->asyncFileContents(cont, filePath, maxSize, offset);
|
||||||
|
|||||||
@@ -362,7 +362,9 @@ void IDevice::iterateDirectory(const FilePath &filePath,
|
|||||||
QTC_CHECK(false);
|
QTC_CHECK(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray IDevice::fileContents(const FilePath &filePath, qint64 limit, qint64 offset) const
|
std::optional<QByteArray> IDevice::fileContents(const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(filePath);
|
Q_UNUSED(filePath);
|
||||||
Q_UNUSED(limit);
|
Q_UNUSED(limit);
|
||||||
@@ -371,9 +373,10 @@ QByteArray IDevice::fileContents(const FilePath &filePath, qint64 limit, qint64
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void IDevice::asyncFileContents(const Continuation<QByteArray> &cont,
|
void IDevice::asyncFileContents(const Continuation<std::optional<QByteArray>> &cont,
|
||||||
const FilePath &filePath,
|
const FilePath &filePath,
|
||||||
qint64 limit, qint64 offset) const
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
cont(fileContents(filePath, limit, offset));
|
cont(fileContents(filePath, limit, offset));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ public:
|
|||||||
virtual void iterateDirectory(const Utils::FilePath &filePath,
|
virtual void iterateDirectory(const Utils::FilePath &filePath,
|
||||||
const std::function<bool(const Utils::FilePath &)> &callBack,
|
const std::function<bool(const Utils::FilePath &)> &callBack,
|
||||||
const Utils::FileFilter &filter) const;
|
const Utils::FileFilter &filter) const;
|
||||||
virtual QByteArray fileContents(const Utils::FilePath &filePath,
|
virtual std::optional<QByteArray> fileContents(const Utils::FilePath &filePath,
|
||||||
qint64 limit,
|
qint64 limit,
|
||||||
qint64 offset) const;
|
qint64 offset) const;
|
||||||
virtual bool writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const;
|
virtual bool writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const;
|
||||||
@@ -253,9 +253,10 @@ public:
|
|||||||
|
|
||||||
virtual void aboutToBeRemoved() const {}
|
virtual void aboutToBeRemoved() const {}
|
||||||
|
|
||||||
virtual void asyncFileContents(const Continuation<QByteArray> &cont,
|
virtual void asyncFileContents(const Continuation<std::optional<QByteArray>> &cont,
|
||||||
const Utils::FilePath &filePath,
|
const Utils::FilePath &filePath,
|
||||||
qint64 limit, qint64 offset) const;
|
qint64 limit,
|
||||||
|
qint64 offset) const;
|
||||||
virtual void asyncWriteFileContents(const Continuation<bool> &cont,
|
virtual void asyncWriteFileContents(const Continuation<bool> &cont,
|
||||||
const Utils::FilePath &filePath,
|
const Utils::FilePath &filePath,
|
||||||
const QByteArray &data) const;
|
const QByteArray &data) const;
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ public:
|
|||||||
|
|
||||||
bool setupShell();
|
bool setupShell();
|
||||||
bool runInShell(const CommandLine &cmd, const QByteArray &data = {});
|
bool runInShell(const CommandLine &cmd, const QByteArray &data = {});
|
||||||
QByteArray outputForRunInShell(const CommandLine &cmd);
|
std::optional<QByteArray> outputForRunInShell(const CommandLine &cmd);
|
||||||
void attachToSharedConnection(SshConnectionHandle *connectionHandle,
|
void attachToSharedConnection(SshConnectionHandle *connectionHandle,
|
||||||
const SshParameters &sshParameters);
|
const SshParameters &sshParameters);
|
||||||
|
|
||||||
@@ -814,10 +814,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call me with shell mutex locked
|
// Call me with shell mutex locked
|
||||||
QByteArray outputForRunInShell(const CommandLine &cmd)
|
std::optional<QByteArray> outputForRunInShell(const CommandLine &cmd)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_shell, return {});
|
QTC_ASSERT(m_shell, return {});
|
||||||
return m_shell->outputForRunInShell(cmd).stdOut;
|
const DeviceShell::RunResult result = m_shell->outputForRunInShell(cmd);
|
||||||
|
if (result.exitCode == 0)
|
||||||
|
return result.stdOut;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSshParameters(const SshParameters &sshParameters)
|
void setSshParameters(const SshParameters &sshParameters)
|
||||||
@@ -1104,7 +1107,7 @@ bool LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArray &da
|
|||||||
return m_handler->runInShell(cmd, data);
|
return m_handler->runInShell(cmd, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray LinuxDevicePrivate::outputForRunInShell(const CommandLine &cmd)
|
std::optional<QByteArray> LinuxDevicePrivate::outputForRunInShell(const CommandLine &cmd)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_shellMutex);
|
QMutexLocker locker(&m_shellMutex);
|
||||||
DEBUG(cmd);
|
DEBUG(cmd);
|
||||||
@@ -1237,7 +1240,8 @@ bool LinuxDevice::renameFile(const FilePath &filePath, const FilePath &target) c
|
|||||||
QDateTime LinuxDevice::lastModified(const FilePath &filePath) const
|
QDateTime LinuxDevice::lastModified(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%Y", filePath.path()}});
|
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%Y", filePath.path()}})
|
||||||
|
.value_or(QByteArray());
|
||||||
const qint64 secs = output.toLongLong();
|
const qint64 secs = output.toLongLong();
|
||||||
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
const QDateTime dt = QDateTime::fromSecsSinceEpoch(secs, Qt::UTC);
|
||||||
return dt;
|
return dt;
|
||||||
@@ -1246,7 +1250,8 @@ QDateTime LinuxDevice::lastModified(const FilePath &filePath) const
|
|||||||
FilePath LinuxDevice::symLinkTarget(const FilePath &filePath) const
|
FilePath LinuxDevice::symLinkTarget(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
const QByteArray output = d->outputForRunInShell({"readlink", {"-n", "-e", filePath.path()}});
|
const QByteArray output = d->outputForRunInShell({"readlink", {"-n", "-e", filePath.path()}})
|
||||||
|
.value_or(QByteArray());
|
||||||
const QString out = QString::fromUtf8(output.data(), output.size());
|
const QString out = QString::fromUtf8(output.data(), output.size());
|
||||||
return output.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
return output.isEmpty() ? FilePath() : filePath.withNewPath(out);
|
||||||
}
|
}
|
||||||
@@ -1254,7 +1259,8 @@ FilePath LinuxDevice::symLinkTarget(const FilePath &filePath) const
|
|||||||
qint64 LinuxDevice::fileSize(const FilePath &filePath) const
|
qint64 LinuxDevice::fileSize(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return -1);
|
QTC_ASSERT(handlesFile(filePath), return -1);
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%s", filePath.path()}});
|
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%s", filePath.path()}})
|
||||||
|
.value_or(QByteArray());
|
||||||
return output.toLongLong();
|
return output.toLongLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1264,7 +1270,7 @@ qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const
|
|||||||
CommandLine cmd("df", {"-k"});
|
CommandLine cmd("df", {"-k"});
|
||||||
cmd.addArg(filePath.path());
|
cmd.addArg(filePath.path());
|
||||||
cmd.addArgs("|tail -n 1 |sed 's/ */ /g'|cut -d ' ' -f 4", CommandLine::Raw);
|
cmd.addArgs("|tail -n 1 |sed 's/ */ /g'|cut -d ' ' -f 4", CommandLine::Raw);
|
||||||
const QByteArray output = d->outputForRunInShell(cmd);
|
const QByteArray output = d->outputForRunInShell(cmd).value_or(QByteArray());
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
const qint64 size = output.toLongLong(&ok);
|
const qint64 size = output.toLongLong(&ok);
|
||||||
if (ok)
|
if (ok)
|
||||||
@@ -1275,7 +1281,8 @@ qint64 LinuxDevice::bytesAvailable(const FilePath &filePath) const
|
|||||||
QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) const
|
QFileDevice::Permissions LinuxDevice::permissions(const FilePath &filePath) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%a", filePath.path()}});
|
const QByteArray output = d->outputForRunInShell({"stat", {"-L", "-c", "%a", filePath.path()}})
|
||||||
|
.value_or(QByteArray());
|
||||||
const uint bits = output.toUInt(nullptr, 8);
|
const uint bits = output.toUInt(nullptr, 8);
|
||||||
QFileDevice::Permissions perm = {};
|
QFileDevice::Permissions perm = {};
|
||||||
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
#define BIT(n, p) if (bits & (1<<n)) perm |= QFileDevice::p
|
||||||
@@ -1305,12 +1312,15 @@ void LinuxDevice::iterateDirectory(const FilePath &filePath,
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return);
|
QTC_ASSERT(handlesFile(filePath), return);
|
||||||
// if we do not have find - use ls as fallback
|
// if we do not have find - use ls as fallback
|
||||||
const QByteArray output = d->outputForRunInShell({"ls", {"-1", "-b", "--", filePath.path()}});
|
const QByteArray output = d->outputForRunInShell({"ls", {"-1", "-b", "--", filePath.path()}})
|
||||||
|
.value_or(QByteArray());
|
||||||
const QStringList entries = QString::fromUtf8(output).split('\n', Qt::SkipEmptyParts);
|
const QStringList entries = QString::fromUtf8(output).split('\n', Qt::SkipEmptyParts);
|
||||||
FileUtils::iterateLsOutput(filePath, entries, filter, callBack);
|
FileUtils::iterateLsOutput(filePath, entries, filter, callBack);
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray LinuxDevice::fileContents(const FilePath &filePath, qint64 limit, qint64 offset) const
|
std::optional<QByteArray> LinuxDevice::fileContents(const FilePath &filePath,
|
||||||
|
qint64 limit,
|
||||||
|
qint64 offset) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(handlesFile(filePath), return {});
|
QTC_ASSERT(handlesFile(filePath), return {});
|
||||||
QString args = "if=" + filePath.path() + " status=none";
|
QString args = "if=" + filePath.path() + " status=none";
|
||||||
@@ -1320,8 +1330,12 @@ QByteArray LinuxDevice::fileContents(const FilePath &filePath, qint64 limit, qin
|
|||||||
}
|
}
|
||||||
CommandLine cmd(FilePath::fromString("dd"), args, CommandLine::Raw);
|
CommandLine cmd(FilePath::fromString("dd"), args, CommandLine::Raw);
|
||||||
|
|
||||||
const QByteArray output = d->outputForRunInShell(cmd);
|
const std::optional<QByteArray> output = d->outputForRunInShell(cmd);
|
||||||
DEBUG(output << QByteArray::fromHex(output));
|
if (output) {
|
||||||
|
DEBUG(*output << QByteArray::fromHex(*output));
|
||||||
|
} else {
|
||||||
|
DEBUG("fileContents failed");
|
||||||
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ public:
|
|||||||
void iterateDirectory(const Utils::FilePath &filePath,
|
void iterateDirectory(const Utils::FilePath &filePath,
|
||||||
const std::function<bool(const Utils::FilePath &)> &callBack,
|
const std::function<bool(const Utils::FilePath &)> &callBack,
|
||||||
const Utils::FileFilter &filter) const override;
|
const Utils::FileFilter &filter) const override;
|
||||||
QByteArray fileContents(const Utils::FilePath &filePath, qint64 limit, qint64 offset) 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) const override;
|
bool writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const override;
|
||||||
QDateTime lastModified(const Utils::FilePath &filePath) const override;
|
QDateTime lastModified(const Utils::FilePath &filePath) const override;
|
||||||
Utils::ProcessInterface *createProcessInterface() const override;
|
Utils::ProcessInterface *createProcessInterface() const override;
|
||||||
|
|||||||
@@ -59,8 +59,8 @@ void tst_fsengine::initTestCase()
|
|||||||
DeviceFileHooks &deviceHooks = DeviceFileHooks::instance();
|
DeviceFileHooks &deviceHooks = DeviceFileHooks::instance();
|
||||||
|
|
||||||
deviceHooks.fileContents =
|
deviceHooks.fileContents =
|
||||||
[](const FilePath &path, qint64 maxSize, qint64 offset) -> QByteArray {
|
[](const FilePath &path, qint64 maxSize, qint64 offset) -> std::optional<QByteArray> {
|
||||||
return FilePath::fromString(path.path()).fileContents(maxSize, offset).value_or(QByteArray());
|
return FilePath::fromString(path.path()).fileContents(maxSize, offset);
|
||||||
};
|
};
|
||||||
|
|
||||||
deviceHooks.isExecutableFile = [](const FilePath &filePath) {
|
deviceHooks.isExecutableFile = [](const FilePath &filePath) {
|
||||||
|
|||||||
Reference in New Issue
Block a user