Skip to content

Commit e252e18

Browse files
committed
Plugin: Remove Plugin dependency on FileSystemIterator
1 parent e03402c commit e252e18

File tree

4 files changed

+170
-45
lines changed

4 files changed

+170
-45
lines changed

Documentation/Libraries/Plugin.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
@note The above code is simplified. For a more complete implementation of an hot-reload system see [SCExample](@ref page_examples) code (`HotReloadSystem.h`).
1414

1515
# Dependencies
16-
- Dependencies: [FileSystemIterator](@ref library_file_system_iterator), [Process](@ref library_process), [Strings](@ref library_strings), [Time](@ref library_time)
17-
- All dependencies: [File](@ref library_file), [FileSystemIterator](@ref library_file_system_iterator), [Foundation](@ref library_foundation), [Process](@ref library_process), [Strings](@ref library_strings), [Time](@ref library_time)
16+
- Dependencies: [Process](@ref library_process), [Strings](@ref library_strings), [Time](@ref library_time)
17+
- All dependencies: [File](@ref library_file), [Foundation](@ref library_foundation), [Process](@ref library_process), [Strings](@ref library_strings), [Time](@ref library_time)
1818

1919
![Dependency Graph](Plugin.svg)
2020

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright (c) Stefano Cristiano
2+
// SPDX-License-Identifier: MIT
3+
#pragma once
4+
#include "../../Strings/Path.h"
5+
6+
#if SC_PLATFORM_WINDOWS
7+
#include <Windows.h>
8+
#else
9+
#include <dirent.h> // opendir, readdir, closedir
10+
#include <sys/stat.h> // stat
11+
#endif
12+
13+
namespace SC
14+
{
15+
struct PluginFileSystemIterator
16+
{
17+
struct Entry
18+
{
19+
StringView name;
20+
bool isDirectory;
21+
};
22+
PluginFileSystemIterator() = default;
23+
~PluginFileSystemIterator() { close(); }
24+
25+
Result init(StringView directoryPath)
26+
{
27+
SC_TRY(directory.assign(directoryPath));
28+
29+
started = false;
30+
pathSeparator = Path::SeparatorStringView();
31+
32+
#if SC_PLATFORM_WINDOWS
33+
StringPath searchPath = directory;
34+
SC_TRY(searchPath.append(pathSeparator));
35+
SC_TRY(searchPath.append("*"));
36+
hFind = ::FindFirstFileW(searchPath.view().getNullTerminatedNative(), &findData);
37+
SC_TRY_MSG(hFind != INVALID_HANDLE_VALUE, "FindFirstFileW failed");
38+
#else
39+
dir = ::opendir(directory.view().getNullTerminatedNative());
40+
SC_TRY_MSG(dir, "opendir failed");
41+
#endif
42+
return Result(true);
43+
}
44+
45+
void close()
46+
{
47+
#if SC_PLATFORM_WINDOWS
48+
if (hFind != INVALID_HANDLE_VALUE)
49+
{
50+
::FindClose(hFind);
51+
hFind = INVALID_HANDLE_VALUE;
52+
}
53+
#else
54+
if (dir)
55+
{
56+
::closedir(dir);
57+
dir = nullptr;
58+
}
59+
#endif
60+
}
61+
62+
bool next(Entry& entry)
63+
{
64+
#if SC_PLATFORM_WINDOWS
65+
if (not started)
66+
{
67+
started = true;
68+
}
69+
else
70+
{
71+
SC_TRY(::FindNextFileW(hFind, &findData) == TRUE);
72+
}
73+
StringSpan nativeName = StringSpan::fromNullTerminated(findData.cFileName, StringEncoding::Utf16);
74+
SC_TRY(currentEntryName.assign(nativeName));
75+
entry.name = currentEntryName.view();
76+
entry.isDirectory = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
77+
return true;
78+
#else
79+
struct dirent* current;
80+
current = ::readdir(dir);
81+
SC_TRY(current != nullptr);
82+
StringView entryName = StringView::fromNullTerminated(current->d_name, StringEncoding::Utf8);
83+
StringPath fullPath = directory;
84+
SC_TRY(fullPath.append(pathSeparator));
85+
SC_TRY(fullPath.append(entryName));
86+
struct stat statBuffer;
87+
const int statRes = ::stat(fullPath.view().getNullTerminatedNative(), &statBuffer);
88+
entry.isDirectory = (statRes == 0 and S_ISDIR(statBuffer.st_mode));
89+
SC_TRY(currentEntryName.assign(entryName));
90+
entry.name = currentEntryName.view();
91+
return true;
92+
#endif
93+
}
94+
95+
StringView pathSeparator;
96+
97+
private:
98+
StringPath directory;
99+
StringPath currentEntryName;
100+
bool started = false;
101+
102+
#if SC_PLATFORM_WINDOWS
103+
HANDLE hFind = INVALID_HANDLE_VALUE;
104+
WIN32_FIND_DATAW findData = {};
105+
#else
106+
DIR* dir = nullptr;
107+
#endif
108+
};
109+
} // namespace SC

Libraries/Plugin/Plugin.cpp

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// SPDX-License-Identifier: MIT
33
#include "Plugin.h"
44

5-
#include "../FileSystemIterator/FileSystemIterator.h"
65
#include "../Foundation/Deferred.h"
76
#include "../Process/Internal/StringsArena.h"
87
#include "../Process/Process.h"
@@ -13,8 +12,10 @@
1312
#if SC_PLATFORM_WINDOWS
1413
#include "Internal/DebuggerWindows.inl"
1514
#include "Internal/VisualStudioPathFinder.h"
15+
1616
#endif
1717
#include "Internal/DynamicLibrary.inl"
18+
#include "Internal/PluginFileSystemIterator.h"
1819

1920
struct SC::PluginCompilerEnvironment::Internal
2021
{
@@ -293,36 +294,52 @@ SC::Result SC::PluginScanner::scanDirectory(const StringView directory, Span<Plu
293294
{
294295
ScannerState scannerState = {definitions};
295296

296-
FileSystemIterator::FolderState recurseStack[16];
297-
FileSystemIterator fsIterator;
298-
fsIterator.options.recursive = false; // Manually recurse only first level dirs
299-
SC_TRY(fsIterator.init(directory, recurseStack));
300-
// Iterate each directory at first level and tentatively build a Plugin PluginDefinition.
301-
// A plugin will be valid if only a single Plugin PluginDefinition will be parsed.
302-
// Both no plugin definition (identity.identifier.isEmpty()) and multiple contradictory plugin
303-
// definitions (multipleDefinitions) will prevent creation of the Plugin PluginDefinition.
304-
while (fsIterator.enumerateNext())
297+
StringPath pathBuffer;
298+
SC_TRY(pathBuffer.assign(directory));
299+
300+
PluginFileSystemIterator iterator;
301+
SC_TRY(iterator.init(directory));
302+
PluginFileSystemIterator::Entry entry;
303+
while (iterator.next(entry))
305304
{
306-
const auto& item = fsIterator.get();
307-
if (item.isDirectory() and item.level == 0)
305+
if (entry.name == SC_NATIVE_STR(".") or entry.name == SC_NATIVE_STR(".."))
308306
{
309-
// Immediately recurse to find candidates (enumerateNext will list files inside this folder)
310-
SC_TRY(fsIterator.recurseSubdirectory());
311-
SC_TRY(scannerState.storeTentativePluginFolder(item.path));
307+
continue; // skip . and ..
312308
}
313-
if (item.level == 1 and StringView(item.name).endsWith(SC_NATIVE_STR(".cpp")))
309+
StringPath fullPath = pathBuffer;
310+
SC_TRY(fullPath.append(iterator.pathSeparator));
311+
SC_TRY(fullPath.append(entry.name));
312+
if (entry.isDirectory)
314313
{
315-
// Inside any of the folder that have been tentatively added
316-
if (scannerState.multipleDefinitions)
314+
// Immediately recurse to find candidates
315+
SC_TRY(scannerState.storeTentativePluginFolder(fullPath.view()));
316+
// Scan subdirectory for .cpp files
317+
PluginFileSystemIterator subIterator;
318+
SC_TRY(subIterator.init(fullPath.view()));
319+
PluginFileSystemIterator::Entry subEntry;
320+
while (subIterator.next(subEntry))
317321
{
318-
continue;
322+
if (subEntry.name == SC_NATIVE_STR(".") or subEntry.name == SC_NATIVE_STR(".."))
323+
{
324+
continue; // skip . and ..
325+
}
326+
StringPath subFullPath = fullPath;
327+
SC_TRY(subFullPath.append(subIterator.pathSeparator));
328+
SC_TRY(subFullPath.append(subEntry.name));
329+
if (!subEntry.isDirectory and subEntry.name.endsWith(SC_NATIVE_STR(".cpp")))
330+
{
331+
// It's a regular file ending with .cpp
332+
if (scannerState.multipleDefinitions)
333+
{
334+
continue;
335+
}
336+
SC_TRY(scannerState.tryParseCandidate(subFullPath.view(), move(tempFileBuffer)));
337+
}
319338
}
320-
SC_TRY(scannerState.tryParseCandidate(item.path, move(tempFileBuffer)));
321339
}
322340
}
323-
324341
scannerState.writeDefinitions(foundDefinitions);
325-
return fsIterator.checkErrors();
342+
return Result(true);
326343
}
327344
#if SC_PLATFORM_WINDOWS
328345
struct SC::PluginCompiler::CompilerFinder
@@ -421,20 +438,21 @@ SC::Result SC::PluginCompiler::findBestCompiler(PluginCompiler& compiler)
421438
CompilerFinder compilerFinder;
422439
for (const auto& basePath : rootPaths)
423440
{
424-
FileSystemIterator::FolderState recurseStack[16];
425-
FileSystemIterator fsIterator;
426-
427-
StringView base = basePath.view();
428-
if (not fsIterator.init(base, recurseStack))
441+
StringView base = basePath.view();
442+
PluginFileSystemIterator iterator;
443+
if (not iterator.init(base))
429444
continue;
430-
while (fsIterator.enumerateNext())
445+
PluginFileSystemIterator::Entry entry;
446+
while (iterator.next(entry))
431447
{
432-
if (fsIterator.get().isDirectory())
448+
if (entry.isDirectory and entry.name != SC_NATIVE_STR(".") and entry.name != SC_NATIVE_STR(".."))
433449
{
434-
const StringView candidate = fsIterator.get().name;
435-
SC_TRY(compilerFinder.tryFindCompiler(base, candidate, compiler));
450+
SC_TRY(compilerFinder.tryFindCompiler(base, entry.name, compiler));
451+
if (compilerFinder.found)
452+
break;
436453
}
437454
}
455+
438456
if (compilerFinder.found)
439457
{
440458
break;
@@ -718,19 +736,21 @@ SC::Result SC::PluginSysroot::findBestSysroot(PluginCompiler::Type compilerType,
718736
StringView baseDirectory = SC_NATIVE_STR("C:\\Program Files (x86)\\Windows Kits\\10");
719737
StringView baseInclude = SC_NATIVE_STR("C:\\Program Files (x86)\\Windows Kits\\10\\include");
720738

721-
FileSystemIterator::FolderState recurseStack[16];
722-
723-
FileSystemIterator fsIterator;
724-
SC_TRY_MSG(fsIterator.init(baseInclude, recurseStack), "Missing Windows Kits 10 directory");
725739
StringPath windowsSdkVersion;
726-
while (fsIterator.enumerateNext())
740+
StringView searchPath = SC_NATIVE_STR("C:\\Program Files (x86)\\Windows Kits\\10\\include");
741+
742+
PluginFileSystemIterator iterator;
743+
SC_TRY(iterator.init(searchPath));
744+
PluginFileSystemIterator::Entry entry;
745+
while (iterator.next(entry))
727746
{
728-
if (fsIterator.get().isDirectory())
747+
if (entry.isDirectory and entry.name != SC_NATIVE_STR(".") and entry.name != SC_NATIVE_STR(".."))
729748
{
730-
SC_TRY(windowsSdkVersion.assign(fsIterator.get().name));
749+
SC_TRY(windowsSdkVersion.assign(entry.name));
731750
break;
732751
}
733752
}
753+
734754
SC_TRY_MSG(not windowsSdkVersion.isEmpty(), "Cannot find Windows Kits 10 include directory")
735755
switch (compilerType)
736756
{
@@ -804,8 +824,7 @@ SC::Result SC::PluginDynamicLibrary::load(const PluginCompiler& compiler, const
804824
::Sleep(400); // Sometimes file is locked...
805825
#endif
806826
lastErrorLogCopy = {errorStorage, sizeof(errorStorage) - 1};
807-
SC_TRY_MSG(compiler.link(definition, sysroot, compilerEnvironment, executablePath, lastErrorLogCopy),
808-
"Link failes");
827+
SC_TRY_MSG(compiler.link(definition, sysroot, compilerEnvironment, executablePath, lastErrorLogCopy), "Link fails");
809828
deferWrite.disarm();
810829
StringPath buffer;
811830
SC_TRY(definition.getDynamicLibraryAbsolutePath(buffer));

Support/Dependencies/Dependencies.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,21 +197,18 @@
197197
},
198198
"Plugin": {
199199
"direct_dependencies": [
200-
"FileSystemIterator",
201200
"Foundation",
202201
"Process",
203202
"Strings",
204203
"Time"
205204
],
206205
"minimal_dependencies": [
207-
"FileSystemIterator",
208206
"Process",
209207
"Strings",
210208
"Time"
211209
],
212210
"all_dependencies": [
213211
"File",
214-
"FileSystemIterator",
215212
"Foundation",
216213
"Process",
217214
"Strings",

0 commit comments

Comments
 (0)