Utils: Introduce a FilePath::refersToExecutableFile

... to avoid the need in user code to care for .exe and .bat suffixes.

Change-Id: Ic249f14273f72c663912482555f98be1af923823
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2022-10-21 10:43:09 +02:00
committed by Christian Stenger
parent 9635b1545b
commit a333efe901
4 changed files with 68 additions and 3 deletions

View File

@@ -4,9 +4,10 @@
#include "devicefileaccess.h" #include "devicefileaccess.h"
#include "algorithm.h" #include "algorithm.h"
#include "qtcassert.h"
#include "hostosinfo.h"
#include "commandline.h" #include "commandline.h"
#include "environment.h"
#include "hostosinfo.h"
#include "qtcassert.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QOperatingSystemVersion> #include <QOperatingSystemVersion>
@@ -244,11 +245,19 @@ qint64 DeviceFileAccess::bytesAvailable(const FilePath &filePath) const
QByteArray DeviceFileAccess::fileId(const FilePath &filePath) const QByteArray DeviceFileAccess::fileId(const FilePath &filePath) const
{ {
Q_UNUSED(filePath); Q_UNUSED(filePath)
QTC_CHECK(false); QTC_CHECK(false);
return {}; return {};
} }
bool DeviceFileAccess::refersToExecutableFile(
const FilePath &filePath,
FilePath::MatchScope matchScope) const
{
Q_UNUSED(matchScope)
return isExecutableFile(filePath);
}
void DeviceFileAccess::asyncFileContents( void DeviceFileAccess::asyncFileContents(
const FilePath &filePath, const FilePath &filePath,
const Continuation<std::optional<QByteArray>> &cont, const Continuation<std::optional<QByteArray>> &cont,
@@ -292,6 +301,40 @@ bool DesktopDeviceFileAccess::isExecutableFile(const FilePath &filePath) const
return fi.isExecutable() && !fi.isDir(); return fi.isExecutable() && !fi.isDir();
} }
static bool isWindowsExecutableHelper(const FilePath &filePath, const QStringView suffix)
{
const QFileInfo fi(filePath.path().append(suffix));
return fi.isExecutable() && !fi.isDir();
}
bool DesktopDeviceFileAccess::refersToExecutableFile(
const FilePath &filePath,
FilePath::MatchScope matchScope) const
{
if (isExecutableFile(filePath))
return true;
if (HostOsInfo::isWindowsHost()) {
if (matchScope == FilePath::WithExeSuffix || matchScope == FilePath::WithExeOrBatSuffix) {
if (isWindowsExecutableHelper(filePath, u".exe"))
return true;
}
if (matchScope == FilePath::WithBatSuffix || matchScope == FilePath::WithExeOrBatSuffix) {
if (isWindowsExecutableHelper(filePath, u".bat"))
return true;
}
if (matchScope == FilePath::WithAnySuffix) {
// That's usually .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH,
static const QStringList exts = qtcEnvironmentVariable("PATHEXT").split(';');
for (const QString &ext : exts) {
if (isWindowsExecutableHelper(filePath, ext))
return true;
}
}
}
return false;
}
bool DesktopDeviceFileAccess::isReadableFile(const FilePath &filePath) const bool DesktopDeviceFileAccess::isReadableFile(const FilePath &filePath) const
{ {
const QFileInfo fi(filePath.path()); const QFileInfo fi(filePath.path());

View File

@@ -47,6 +47,10 @@ protected:
virtual qint64 bytesAvailable(const FilePath &filePath) const; virtual qint64 bytesAvailable(const FilePath &filePath) const;
virtual QByteArray fileId(const FilePath &filePath) const; virtual QByteArray fileId(const FilePath &filePath) const;
virtual bool refersToExecutableFile(
const FilePath &filePath,
FilePath::MatchScope matchScope) const;
virtual void iterateDirectory( virtual void iterateDirectory(
const FilePath &filePath, const FilePath &filePath,
const FilePath::IterateDirCallback &callBack, const FilePath::IterateDirCallback &callBack,
@@ -114,6 +118,10 @@ protected:
qint64 bytesAvailable(const FilePath &filePath) const override; qint64 bytesAvailable(const FilePath &filePath) const override;
QByteArray fileId(const FilePath &filePath) const override; QByteArray fileId(const FilePath &filePath) const override;
bool refersToExecutableFile(
const FilePath &filePath,
FilePath::MatchScope matchScope) const override;
void iterateDirectory( void iterateDirectory(
const FilePath &filePath, const FilePath &filePath,
const FilePath::IterateDirCallback &callBack, const FilePath::IterateDirCallback &callBack,

View File

@@ -396,6 +396,16 @@ bool FilePath::isExecutableFile() const
return fileAccess()->isExecutableFile(*this); return fileAccess()->isExecutableFile(*this);
} }
/// \returns a bool indicating on whether a process with this FilePath's
/// .nativePath() is likely to start.
///
/// This is equivalent to \c isExecutableFile() in general.
/// On Windows, it will check appending various suffixes, too.
bool FilePath::refersToExecutableFile(MatchScope matchScope) const
{
return fileAccess()->refersToExecutableFile(*this, matchScope);
}
bool FilePath::isReadableFile() const bool FilePath::isReadableFile() const
{ {
return fileAccess()->isReadableFile(*this); return fileAccess()->isReadableFile(*this);

View File

@@ -179,6 +179,10 @@ public:
[[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {}, [[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {},
PathAmending = AppendToPath) const; PathAmending = AppendToPath) const;
enum MatchScope { ExactMatchOnly, WithExeSuffix, WithBatSuffix,
WithExeOrBatSuffix, WithAnySuffix };
bool refersToExecutableFile(MatchScope considerScript) const;
// makes sure that capitalization of directories is canonical // makes sure that capitalization of directories is canonical
// on Windows and macOS. This is rarely needed. // on Windows and macOS. This is rarely needed.
[[nodiscard]] FilePath normalizedPathName() const; [[nodiscard]] FilePath normalizedPathName() const;