From ae26fa0dd736768477f00731dc2a66ca1d0d9b59 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 23 May 2023 09:14:23 +0200 Subject: [PATCH] Utils: Add a FilePath::searchAllInDirectories A variation that does not stop on the first found item. Useful for auto-detection scenarios. Use "WithAnySuffix" as default to cover .cmd and .bat etc. Change-Id: I48f36eff06699c046e34c8e2646546bcff20ae8b Reviewed-by: Marcus Tillmanns --- src/libs/utils/filepath.cpp | 74 +++++++++++++++++++++++++++++++++---- src/libs/utils/filepath.h | 11 +++++- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index fa91a09d054..2df57830343 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1538,25 +1538,83 @@ FilePath FilePath::searchInDirectories(const FilePaths &dirs, return {}; } -FilePath FilePath::searchInPath(const FilePaths &additionalDirs, - PathAmending amending, - const FilePathPredicate &filter, - const MatchScope &matchScope) const +FilePaths FilePath::searchAllInDirectories(const FilePaths &dirs, + const FilePathPredicate &filter, + const MatchScope &matchScope) const { - if (isAbsolutePath()) - return *this; + if (isEmpty()) + return {}; - FilePaths directories = devicePathEnvironmentVariable(); + const FilePaths execs = appendExeExtensions(*this, matchScope); + + FilePaths result; + if (isAbsolutePath()) { + for (const FilePath &filePath : execs) { + if (filePath.isExecutableFile() && (!filter || filter(filePath))) + result.append(filePath); + } + return result; + } + + QSet alreadyCheckedDirectories; + + for (const FilePath &dir : dirs) { + // Compare the initial size of the set with the size after insertion to check + // if the directory was already checked. + const int initialCount = alreadyCheckedDirectories.count(); + alreadyCheckedDirectories.insert(dir); + const bool wasAlreadyChecked = alreadyCheckedDirectories.count() == initialCount; + + if (dir.isEmpty() || wasAlreadyChecked) + continue; + + for (const FilePath &exe : execs) { + const FilePath filePath = dir / exe.path(); + if (filePath.isExecutableFile() && (!filter || filter(filePath))) + result.append(filePath); + } + } + + return result; +} + +static FilePaths dirsFromPath(const FilePath &anchor, + const FilePaths &additionalDirs, + FilePath::PathAmending amending) +{ + FilePaths directories = anchor.devicePathEnvironmentVariable(); if (!additionalDirs.isEmpty()) { - if (amending == AppendToPath) + if (amending == FilePath::AppendToPath) directories.append(additionalDirs); else directories = additionalDirs + directories; } + + return directories; +} + +FilePath FilePath::searchInPath(const FilePaths &additionalDirs, + PathAmending amending, + const FilePathPredicate &filter, + MatchScope matchScope) const +{ + if (isAbsolutePath()) + return *this; + + const FilePaths directories = dirsFromPath(*this, additionalDirs, amending); return searchInDirectories(directories, filter, matchScope); } +FilePaths FilePath::searchAllInPath(const FilePaths &additionalDirs, + PathAmending amending, + const FilePathPredicate &filter, + MatchScope matchScope) const +{ + const FilePaths directories = dirsFromPath(*this, additionalDirs, amending); + return searchAllInDirectories(directories, filter, matchScope); +} + Environment FilePath::deviceEnvironment() const { if (needsDevice()) { diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 2a41c6c615b..4462b473cdd 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -187,11 +187,18 @@ public: [[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs, const FilePathPredicate &filter = {}, - const MatchScope &matchScope = {}) const; + const MatchScope &matchScope = WithAnySuffix) const; + [[nodiscard]] FilePaths searchAllInDirectories(const FilePaths &dirs, + const FilePathPredicate &filter = {}, + const MatchScope &matchScope = WithAnySuffix) const; [[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {}, PathAmending = AppendToPath, const FilePathPredicate &filter = {}, - const MatchScope &matchScope = {}) const; + MatchScope matchScope = WithAnySuffix) const; + [[nodiscard]] FilePaths searchAllInPath(const FilePaths &additionalDirs = {}, + PathAmending = AppendToPath, + const FilePathPredicate &filter = {}, + MatchScope matchScope = WithAnySuffix) const; std::optional refersToExecutableFile(MatchScope considerScript) const;