1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-13 00:04:19 +00:00

Projucer: Refactored module scanning code and added AvailableModuleList class for asynchronous scanning

This commit is contained in:
ed 2018-08-23 14:15:28 +01:00
parent 8632d853e9
commit f77c995b4d
19 changed files with 502 additions and 432 deletions

View file

@ -25,10 +25,9 @@
*/
#include "../Application/jucer_Headers.h"
#include "jucer_Module.h"
#include "../ProjectSaving/jucer_ProjectSaver.h"
#include "../ProjectSaving/jucer_ProjectExport_Xcode.h"
#include "../Application/jucer_ProjucerAnalytics.h"
#include "../Application/jucer_Application.h"
//==============================================================================
static var parseModuleDesc (const StringArray& lines)
@ -113,195 +112,154 @@ StringArray ModuleDescription::getDependencies() const
}
//==============================================================================
ModuleList::ModuleList()
{
}
ModuleList::ModuleList (const ModuleList& other)
{
operator= (other);
}
ModuleList& ModuleList::operator= (const ModuleList& other)
{
modules.clear();
modules.addCopiesOf (other.modules);
return *this;
}
const ModuleDescription* ModuleList::getModuleWithID (const String& moduleID) const
{
for (auto* m : modules)
if (m->getID() == moduleID)
return m;
return nullptr;
}
void ModuleList::sort()
{
std::sort (modules.begin(), modules.end(), [] (const ModuleDescription* m1, const ModuleDescription* m2)
{
return m1->getID().compareIgnoreCase (m2->getID()) < 0;
});
}
StringArray ModuleList::getIDs() const
{
StringArray results;
for (auto* m : modules)
results.add (m->getID());
results.sort (true);
return results;
}
bool ModuleList::tryToAddModuleFromFolder (const File& path)
static bool tryToAddModuleFromFolder (const File& path, ModuleIDAndFolderList& list)
{
ModuleDescription m (path);
if (m.isValid())
{
getPreviousModuleDirectories().addIfNotAlreadyThere (path.getParentDirectory());
modules.add (new ModuleDescription (m));
list.push_back ({ m.getID(), path });
return true;
}
return false;
}
void ModuleList::addAllModulesInFolder (const File& path)
static bool addAllModulesInSubfoldersRecursively (const File& path, int depth, ModuleIDAndFolderList& list)
{
if (! tryToAddModuleFromFolder (path))
if (depth > 0)
{
for (DirectoryIterator iter (path, false, "*", File::findDirectories); iter.next();)
tryToAddModuleFromFolder (iter.getFile().getLinkedTarget());
{
if (auto* job = ThreadPoolJob::getCurrentThreadPoolJob())
if (job->shouldExit())
return false;
auto childPath = iter.getFile().getLinkedTarget();
if (! tryToAddModuleFromFolder (childPath, list))
if (! addAllModulesInSubfoldersRecursively (childPath, depth - 1, list))
return false;
}
}
return true;
}
Array<File>& ModuleList::getPreviousModuleDirectories()
static bool addAllModulesInFolder (const File& path, ModuleIDAndFolderList& list)
{
static Array<File> previous;
return previous;
}
bool exitedBeforeCompletion = false;
File ModuleList::tryToFindModulePathFromPrevious (const String& id)
{
for (auto& f : getPreviousModuleDirectories())
if (! tryToAddModuleFromFolder (path, list))
{
auto modulePath = f.getChildFile (id);
if (ModuleDescription (modulePath).isValid())
return modulePath;
int subfolders = 3;
exitedBeforeCompletion = addAllModulesInSubfoldersRecursively (path, subfolders, list);
}
return {};
return exitedBeforeCompletion;
}
static void sort (ModuleIDAndFolderList& listToSort)
{
std::sort (listToSort.begin(), listToSort.end(), [] (const ModuleIDAndFolder& m1, const ModuleIDAndFolder& m2)
{
return m1.first.compareIgnoreCase (m2.first) < 0;
});
}
//==============================================================================
static File getModuleFolderFromPathIfItExists (const String& path, const String& moduleID)
struct ModuleScannerJob : public ThreadPoolJob
{
if (path.isNotEmpty())
ModuleScannerJob (const Array<File>& paths, std::function<void (const ModuleIDAndFolderList&)>&& callback)
: ThreadPoolJob ("ModuleScannerJob"),
pathsToScan (paths),
completionCallback (std::move (callback))
{
ModuleList list;
list.addAllModulesInFolder (path);
if (auto* desc = list.getModuleWithID (moduleID))
return desc->getFolder();
}
JobStatus runJob() override
{
ModuleIDAndFolderList list;
for (auto& p : pathsToScan)
if (! addAllModulesInFolder (p, list))
return jobNeedsRunningAgain;
sort (list);
completionCallback (list);
return jobHasFinished;
}
Array<File> pathsToScan;
std::function<void (const ModuleIDAndFolderList&)> completionCallback;
};
AvailableModuleList::AvailableModuleList()
{
}
ThreadPoolJob* AvailableModuleList::createScannerJob (const Array<File>& paths)
{
return new ModuleScannerJob (paths, [this] (ModuleIDAndFolderList scannedModuleList)
{
{
const ScopedLock swapLock (lock);
moduleList.swap (scannedModuleList);
}
MessageManager::callAsync ([this] { listeners.call ([] (Listener& l) { l.availableModulesChanged(); }); });
});
}
void AvailableModuleList::removePendingAndAddJob (ThreadPoolJob* jobToAdd)
{
scanPool.removeAllJobs (false, 100);
scanPool.addJob (jobToAdd, true);
}
void AvailableModuleList::scanPaths (const Array<File>& paths)
{
auto* job = createScannerJob (paths);
removePendingAndAddJob (job);
scanPool.waitForJobToFinish (job, -1);
}
void AvailableModuleList::scanPathsAsync (const Array<File>& paths)
{
removePendingAndAddJob (createScannerJob (paths));
}
ModuleIDAndFolderList AvailableModuleList::getAllModules() const
{
const ScopedLock readLock (lock);
return moduleList;
}
ModuleIDAndFolder AvailableModuleList::getModuleWithID (const String& id) const
{
const ScopedLock readLock (lock);
for (auto& mod : moduleList)
if (mod.first == id)
return mod;
return {};
}
static Array<File> getAllPossibleModulePathsFromExporters (Project& project, bool onlyThisOS)
void AvailableModuleList::removeDuplicates (const ModuleIDAndFolderList& other)
{
StringArray paths;
const ScopedLock readLock (lock);
for (Project::ExporterIterator exporter (project); exporter.next();)
for (auto& m : other)
{
if (onlyThisOS && ! exporter->mayCompileOnCurrentOS())
continue;
auto pos = std::find (moduleList.begin(), moduleList.end(), m);
auto& modules = project.getModules();
auto n = modules.getNumModules();
for (int i = 0; i < n; ++i)
{
auto id = modules.getModuleID (i);
if (modules.shouldUseGlobalPath (id))
continue;
auto path = exporter->getPathForModuleString (id);
if (path.isNotEmpty())
paths.addIfNotAlreadyThere (path);
}
auto oldPath = exporter->getLegacyModulePath();
if (oldPath.isNotEmpty())
paths.addIfNotAlreadyThere (oldPath);
if (pos != moduleList.end())
moduleList.erase (pos);
}
Array<File> files;
for (auto& path : paths)
{
auto f = project.resolveFilename (path);
if (f.isDirectory())
{
files.addIfNotAlreadyThere (f);
if (f.getChildFile ("modules").isDirectory())
files.addIfNotAlreadyThere (f.getChildFile ("modules"));
}
}
return files;
}
void ModuleList::scanProjectExporterModulePaths (Project& project)
{
modules.clear();
for (auto& m : getAllPossibleModulePathsFromExporters (project, false))
addAllModulesInFolder (m);
sort();
}
void ModuleList::scanGlobalJuceModulePath()
{
modules.clear();
auto& settings = getAppSettings();
auto path = settings.getStoredPath (Ids::defaultJuceModulePath).toString();
if (path.isNotEmpty())
addAllModulesInFolder ({ path });
sort();
}
void ModuleList::scanGlobalUserModulePath()
{
modules.clear();
auto paths = StringArray::fromTokens (getAppSettings().getStoredPath (Ids::defaultUserModulePath).toString(), ";", {});
for (auto p : paths)
{
p = p.replace ("~", File::getSpecialLocation (File::userHomeDirectory).getFullPathName());
auto f = File::createFileWithoutCheckingPath (p.trim());
if (f.exists())
addAllModulesInFolder (f);
}
sort();
}
//==============================================================================
@ -314,7 +272,7 @@ LibraryModule::LibraryModule (const ModuleDescription& d)
void LibraryModule::writeIncludes (ProjectSaver& projectSaver, OutputStream& out)
{
auto& project = projectSaver.project;
auto& modules = project.getModules();
auto& modules = project.getEnabledModules();
auto id = getID();
@ -382,7 +340,7 @@ void LibraryModule::addSettingsForModuleToExporter (ProjectExporter& exporter, P
{
Array<File> compiled;
auto& modules = project.getModules();
auto& modules = project.getEnabledModules();
auto id = getID();
auto localModuleFolder = modules.shouldCopyModuleFilesLocally (id).getValue() ? project.getLocalModuleFolder (id)
@ -649,7 +607,7 @@ EnabledModuleList::EnabledModuleList (Project& p, const ValueTree& s)
ModuleDescription EnabledModuleList::getModuleInfo (const String& moduleID)
{
return ModuleDescription (findFolderForModule (moduleID));
return ModuleDescription (project.getModuleWithID (moduleID).second);
}
bool EnabledModuleList::isModuleEnabled (const String& moduleID) const
@ -681,48 +639,6 @@ Value EnabledModuleList::shouldShowAllModuleFilesInProject (const String& module
.getPropertyAsValue (Ids::showAllCode, getUndoManager());
}
File EnabledModuleList::findFolderForModule (const String& moduleID)
{
if (shouldUseGlobalPath (moduleID))
{
if (isJUCEModule (moduleID))
return File (getAppSettings().getStoredPath (Ids::defaultJuceModulePath).toString()).getChildFile (moduleID);
{
auto previous = ModuleList::tryToFindModulePathFromPrevious (moduleID);
if (previous != File())
return previous;
}
ModuleList list;
list.scanGlobalUserModulePath();
if (auto* desc = list.getModuleWithID (moduleID))
return desc->getFolder();
}
else
{
for (auto p : getAllPossibleModulePathsFromExporters (project, true))
{
auto f = getModuleFolderFromPathIfItExists (p.getFullPathName(), moduleID);
if (f != File())
return f;
}
for (auto p : getAllPossibleModulePathsFromExporters (project, false))
{
auto f = getModuleFolderFromPathIfItExists (p.getFullPathName(), moduleID);
if (f != File())
return f;
}
}
return {};
}
struct ModuleTreeSorter
{
static int compareElements (const ValueTree& m1, const ValueTree& m2)
@ -754,7 +670,7 @@ void EnabledModuleList::addModule (const File& moduleFolder, bool copyLocally, b
if (! isModuleEnabled (moduleID))
{
ValueTree module (Ids::MODULE);
module.setProperty (Ids::ID, moduleID, nullptr);
module.setProperty (Ids::ID, moduleID, getUndoManager());
state.appendChild (module, getUndoManager());
sortAlphabetically();
@ -769,6 +685,9 @@ void EnabledModuleList::addModule (const File& moduleFolder, bool copyLocally, b
for (Project::ExporterIterator exporter (project); exporter.next();)
exporter->getPathForModuleValue (moduleID) = path.toUnixStyle();
if (! useGlobalPath)
project.rescanExporterPathModules (false);
if (sendAnalyticsEvent)
{
StringPairArray data;
@ -808,7 +727,7 @@ StringArray EnabledModuleList::getAllModules() const
static void getDependencies (Project& project, const String& moduleID, StringArray& dependencies)
{
auto info = project.getModules().getModuleInfo (moduleID);
auto info = project.getEnabledModules().getModuleInfo (moduleID);
for (auto uid : info.getDependencies())
{
@ -877,7 +796,7 @@ bool EnabledModuleList::areMostModulesCopiedLocally() const
void EnabledModuleList::setLocalCopyModeForAllModules (bool copyLocally)
{
for (auto i = getNumModules(); --i >= 0;)
shouldCopyModuleFilesLocally (project.getModules().getModuleID (i)) = copyLocally;
shouldCopyModuleFilesLocally (project.getEnabledModules().getModuleID (i)) = copyLocally;
}
File EnabledModuleList::findDefaultModulesFolder (Project& project)
@ -887,12 +806,9 @@ File EnabledModuleList::findDefaultModulesFolder (Project& project)
if (globalPath != File())
return globalPath;
ModuleList available;
available.scanProjectExporterModulePaths (project);
for (auto i = available.modules.size(); --i >= 0;)
for (auto& exporterPathModule : project.getExporterPathsModuleList().getAllModules())
{
auto f = available.modules.getUnchecked(i)->getFolder();
auto f = exporterPathModule.second;
if (f.isDirectory())
return f.getParentDirectory();
@ -916,27 +832,15 @@ void EnabledModuleList::addModuleFromUserSelectedFile()
void EnabledModuleList::addModuleInteractive (const String& moduleID)
{
ModuleList list;
auto f = project.getModuleWithID (moduleID).second;
list.scanGlobalJuceModulePath();
if (auto* info = list.getModuleWithID (moduleID))
if (f != File())
{
addModule (info->moduleFolder, areMostModulesCopiedLocally(), areMostModulesUsingGlobalPath(), true);
addModule (f, areMostModulesCopiedLocally(), areMostModulesUsingGlobalPath(), true);
return;
}
list.scanGlobalUserModulePath();
if (auto* info = list.getModuleWithID (moduleID))
{
addModule (info->moduleFolder, areMostModulesCopiedLocally(), areMostModulesUsingGlobalPath(), true);
return;
}
list.scanProjectExporterModulePaths (project);
if (auto* info = list.getModuleWithID (moduleID))
addModule (info->moduleFolder, areMostModulesCopiedLocally(), false, true);
else
addModuleFromUserSelectedFile();
addModuleFromUserSelectedFile();
}
void EnabledModuleList::addModuleOfferingToCopy (const File& f, bool isFromUserSpecifiedFolder)