1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #pragma once
27
28 #include "projectnodes.h"
29
30 #include <coreplugin/iversioncontrol.h>
31 #include <coreplugin/vcsmanager.h>
32
33 #include <utils/algorithm.h>
34 #include <utils/fileutils.h>
35
36 namespace ProjectExplorer {
37
38 template<typename Result>
39 QList<FileNode *> scanForFiles(QFutureInterface<Result> &future,
40 const Utils::FilePath &directory,
41 const std::function<FileNode *(const Utils::FilePath &)> factory);
42
43 // IMPLEMENTATION:
44
45 namespace Internal {
46 template<typename Result>
scanForFilesRecursively(QFutureInterface<Result> & future,double progressStart,double progressRange,const Utils::FilePath & directory,const std::function<FileNode * (const Utils::FilePath &)> factory,QSet<QString> & visited,const QList<Core::IVersionControl * > & versionControls)47 QList<FileNode *> scanForFilesRecursively(
48 QFutureInterface<Result> &future,
49 double progressStart,
50 double progressRange,
51 const Utils::FilePath &directory,
52 const std::function<FileNode *(const Utils::FilePath &)> factory,
53 QSet<QString> &visited,
54 const QList<Core::IVersionControl *> &versionControls)
55 {
56 QList<FileNode *> result;
57
58 const QDir baseDir = QDir(directory.toString());
59
60 // Do not follow directory loops:
61 const int visitedCount = visited.count();
62 visited.insert(baseDir.canonicalPath());
63 if (visitedCount == visited.count())
64 return result;
65
66 const QFileInfoList entries = baseDir.entryInfoList(QStringList(),
67 QDir::AllEntries | QDir::NoDotAndDotDot);
68 double progress = 0;
69 const double progressIncrement = progressRange / static_cast<double>(entries.count());
70 int lastIntProgress = 0;
71 for (const QFileInfo &entry : entries) {
72 if (future.isCanceled())
73 return result;
74
75 const Utils::FilePath entryName = Utils::FilePath::fromString(entry.absoluteFilePath());
76 if (!Utils::contains(versionControls, [&entryName](const Core::IVersionControl *vc) {
77 return vc->isVcsFileOrDirectory(entryName);
78 })) {
79 if (entry.isDir())
80 result.append(scanForFilesRecursively(future,
81 progress,
82 progressIncrement,
83 entryName,
84 factory,
85 visited,
86 versionControls));
87 else if (FileNode *node = factory(entryName))
88 result.append(node);
89 }
90 progress += progressIncrement;
91 const int intProgress = std::min(static_cast<int>(progressStart + progress),
92 future.progressMaximum());
93 if (lastIntProgress < intProgress) {
94 future.setProgressValue(intProgress);
95 lastIntProgress = intProgress;
96 }
97 }
98 future.setProgressValue(
99 std::min(static_cast<int>(progressStart + progressRange), future.progressMaximum()));
100 return result;
101 }
102 } // namespace Internal
103
104 template<typename Result>
scanForFiles(QFutureInterface<Result> & future,const Utils::FilePath & directory,const std::function<FileNode * (const Utils::FilePath &)> factory)105 QList<FileNode *> scanForFiles(QFutureInterface<Result> &future,
106 const Utils::FilePath &directory,
107 const std::function<FileNode *(const Utils::FilePath &)> factory)
108 {
109 QSet<QString> visited;
110 future.setProgressRange(0, 1000000);
111 return Internal::scanForFilesRecursively(future,
112 0.0,
113 1000000.0,
114 directory,
115 factory,
116 visited,
117 Core::VcsManager::versionControls());
118 }
119
120 } // namespace ProjectExplorer
121