Files
Sourcetrail/src/lib/Project.cpp
T
malte_langkabel f06dd6abc5 logic: improved indexer parallelization
* added task that injects into PersistentStorage parallel to indexer tasks.
* added Blackboard for Task classes
2016-09-12 11:52:14 +02:00

357 lines
8.8 KiB
C++

#include "Project.h"
#include "component/view/DialogView.h"
#include "data/access/StorageAccessProxy.h"
#include "data/parser/cxx/TaskParseWrapper.h"
#include "data/parser/java/TaskParseJava.h"
#include "data/StorageProvider.h"
#include "data/PersistentStorage.h"
#include "data/TaskCleanStorage.h"
#include "data/TaskInjectStorage.h"
#include "settings/ApplicationSettings.h"
#include "settings/ProjectSettings.h"
#include "utility/file/FileRegister.h"
#include "utility/messaging/type/MessageFinishedParsing.h"
#include "utility/messaging/type/MessageRefresh.h"
#include "utility/messaging/type/MessageStatus.h"
#include "utility/scheduling/TaskGroupSequential.h"
#include "utility/scheduling/TaskGroupParallel.h"
#include "utility/scheduling/TaskRepeatWhileSuccess.h"
#include "utility/text/TextAccess.h"
#include "utility/utility.h"
#include "utility/utilityString.h"
#include "utility/Version.h"
#include "Application.h"
#include "CxxProject.h"
#include "JavaProject.h"
#include "isTrial.h"
std::shared_ptr<Project> Project::create(
const FilePath& projectSettingsFile, StorageAccessProxy* storageAccessProxy, DialogView* dialogView)
{
std::shared_ptr<Project> project;
switch (ProjectSettings::getLanguageOfProject(projectSettingsFile))
{
case LANGUAGE_C:
case LANGUAGE_CPP:
{
project = std::shared_ptr<CxxProject>(new CxxProject(
std::make_shared<CxxProjectSettings>(projectSettingsFile), storageAccessProxy, dialogView
));
}
break;
case LANGUAGE_JAVA:
{
project = std::shared_ptr<JavaProject>(new JavaProject(
std::make_shared<JavaProjectSettings>(projectSettingsFile), storageAccessProxy, dialogView
));
}
break;
default:
break;
}
if (project)
{
project->load();
}
return project;
}
Project::~Project()
{
}
bool Project::refresh(bool forceRefresh)
{
if (m_state == PROJECT_STATE_NOT_LOADED)
{
return false;
}
std::string question;
if (!forceRefresh)
{
switch (m_state)
{
case PROJECT_STATE_EMPTY:
forceRefresh = true;
break;
case PROJECT_STATE_LOADED:
break;
case PROJECT_STATE_OUTDATED:
question =
"The project file was changed after the last indexing. The project needs to get fully reindexed to "
"reflect the current project state. Do you want to reindex the project?";
forceRefresh = true;
break;
case PROJECT_STATE_OUTVERSIONED:
question =
"This project was indexed with a different version of Coati. It needs to be fully reindexed to be used "
"with this version of Coati. Do you want to reindex the project?";
forceRefresh = true;
break;
case PROJECT_STATE_SETTINGS_UPDATED:
question =
"Some settings were changed, the project needs to be fully reindexed. "
"Do you want to reindex the project?";
forceRefresh = true;
break;
default:
break;
}
}
if (forceRefresh && question.size() && Application::getInstance()->hasGUI() && !isTrial())
{
std::vector<std::string> options;
options.push_back("Yes");
options.push_back("No");
int result = m_dialogView->confirm(question, options);
if (result == 1)
{
return false;
}
}
if (!prepareRefresh())
{
return false;
}
getProjectSettings()->reload();
updateFileManager(m_fileManager);
if (buildIndex(forceRefresh))
{
m_storageAccessProxy->setSubject(m_storage.get());
m_state = PROJECT_STATE_LOADED;
return true;
}
return false;
}
FilePath Project::getProjectSettingsFilePath() const
{
return getProjectSettings()->getFilePath();
}
LanguageType Project::getLanguage() const
{
return getProjectSettings()->getLanguage();
}
std::string Project::getDescription() const
{
return getProjectSettings()->getDescription();
}
bool Project::settingsEqualExceptNameAndLocation(const ProjectSettings& otherSettings) const
{
return getProjectSettings()->equalsExceptNameAndLocation(otherSettings);
}
void Project::setStateSettingsUpdated()
{
if (m_state != PROJECT_STATE_NOT_LOADED && m_state != PROJECT_STATE_EMPTY)
{
m_state = PROJECT_STATE_SETTINGS_UPDATED;
}
}
void Project::logStats() const
{
m_storage->logStats();
}
Project::Project(StorageAccessProxy* storageAccessProxy, DialogView* dialogView)
: m_storageAccessProxy(storageAccessProxy)
, m_dialogView(dialogView)
, m_state(PROJECT_STATE_NOT_LOADED)
{
}
DialogView* Project::getDialogView() const
{
return m_dialogView;
}
const std::vector<FilePath>& Project::getSourcePaths() const
{
return m_fileManager.getSourcePaths();
}
void Project::load()
{
m_storageAccessProxy->setSubject(nullptr);
const std::shared_ptr<ProjectSettings> projectSettings = getProjectSettings();
bool loadedSettings = projectSettings->reload();
if (!loadedSettings)
{
return;
}
NameHierarchy::setDelimiter(getSymbolNameDelimiterForLanguage(projectSettings->getLanguage()));
const FilePath projectSettingsPath = projectSettings->getFilePath();
const FilePath dbPath = FilePath(projectSettingsPath).replaceExtension("coatidb");
m_storage = std::make_shared<PersistentStorage>(dbPath);
if (m_storage->isEmpty())
{
m_state = PROJECT_STATE_EMPTY;
m_storage->setup();
}
else if (m_storage->isIncompatible())
{
m_state = PROJECT_STATE_OUTVERSIONED;
}
else if (TextAccess::createFromFile(projectSettingsPath.str())->getText() != m_storage->getProjectSettingsText())
{
m_state = PROJECT_STATE_OUTDATED;
}
else
{
m_state = PROJECT_STATE_LOADED;
}
if (m_state == PROJECT_STATE_LOADED || m_state == PROJECT_STATE_OUTDATED)
{
m_storage->finishParsing();
m_storageAccessProxy->setSubject(m_storage.get());
MessageFinishedParsing().dispatch();
MessageStatus("Finished Loading", false, false).dispatch();
}
else
{
MessageStatus("Project not loaded", false, false).dispatch();
}
if (m_state != PROJECT_STATE_LOADED)
{
MessageRefresh().dispatch();
}
}
bool Project::buildIndex(bool forceRefresh)
{
if (!prepareIndexing())
{
return false;
}
m_fileManager.fetchFilePaths(
forceRefresh ? std::vector<FileInfo>() : m_storage->getInfoOnAllFiles()
);
std::set<FilePath> addedFilePaths = m_fileManager.getAddedFilePaths();
std::set<FilePath> updatedFilePaths = m_fileManager.getUpdatedFilePaths();
std::set<FilePath> removedFilePaths = m_fileManager.getRemovedFilePaths();
if (!forceRefresh)
{
utility::append(updatedFilePaths, m_storage->getDependingFilePaths(updatedFilePaths));
utility::append(updatedFilePaths, m_storage->getDependingFilePaths(removedFilePaths));
}
std::vector<FilePath> filesToClean;
filesToClean.insert(filesToClean.end(), removedFilePaths.begin(), removedFilePaths.end());
filesToClean.insert(filesToClean.end(), updatedFilePaths.begin(), updatedFilePaths.end());
std::vector<FilePath> filesToParse;
filesToParse.insert(filesToParse.end(), addedFilePaths.begin(), addedFilePaths.end());
filesToParse.insert(filesToParse.end(), updatedFilePaths.begin(), updatedFilePaths.end());
if (!filesToClean.size() && !filesToParse.size())
{
MessageStatus("Nothing to refresh, all files are up-to-date.").dispatch();
return false;
}
if (Application::getInstance()->hasGUI())
{
bool doIndex = m_dialogView->startIndexingDialog(filesToClean.size(), filesToParse.size());
if (!doIndex)
{
return false;
}
}
if (forceRefresh)
{
m_storage->clear();
}
m_storage->setProjectSettingsText(TextAccess::createFromFile(getProjectSettingsFilePath().str())->getText());
std::shared_ptr<TaskGroupSequential> taskSequential = std::make_shared<TaskGroupSequential>();
if (filesToClean.size())
{
taskSequential->addTask(std::make_shared<TaskCleanStorage>(m_storage.get(), filesToClean, m_dialogView));
}
const int indexerThreadCount = ApplicationSettings::getInstance()->getIndexerThreadCount();
std::shared_ptr<FileRegister> fileRegister = std::make_shared<FileRegister>(&m_fileManager, indexerThreadCount > 1);
fileRegister->setFilePaths(filesToParse);
std::shared_ptr<TaskParseWrapper> taskParserWrapper = std::make_shared<TaskParseWrapper>(
m_storage.get(),
fileRegister,
m_dialogView
);
taskSequential->addTask(taskParserWrapper);
std::shared_ptr<TaskGroupParallel> taskParallelIndexing = std::make_shared<TaskGroupParallel>();
taskParserWrapper->setTask(taskParallelIndexing);
std::shared_ptr<StorageProvider> storageProvider = std::make_shared<StorageProvider>();
for (int i = 0; i < indexerThreadCount; i++)
{
std::shared_ptr<TaskRepeatWhileSuccess> taskRepeat = std::make_shared<TaskRepeatWhileSuccess>();
taskParallelIndexing->addTask(taskRepeat);
taskRepeat->setTask(createIndexerTask(storageProvider, fileRegister));
}
std::shared_ptr<TaskRepeatWhileSuccess> taskRepeat = std::make_shared<TaskRepeatWhileSuccess>();
taskParallelIndexing->addTask(taskRepeat);
taskRepeat->setTask(std::make_shared<TaskInjectStorage>(storageProvider, m_storage));
Task::dispatch(taskSequential);
return true;
}
bool Project::prepareIndexing()
{
return true;
}
bool Project::prepareRefresh()
{
return true;
}