From c4a355aa814d72b5c7892ab97c6df0e08a98236b Mon Sep 17 00:00:00 2001 From: Allan CORNET Date: Mon, 2 Aug 2021 22:07:45 +0200 Subject: [PATCH] fix #477 update files watcher. --- CHANGELOG.md | 2 + .../interpreter/src/c/nlsInterpreter.vcxproj | 1 + .../src/c/nlsInterpreter.vcxproj.filters | 3 + modules/interpreter/src/cpp/Evaluator.cpp | 3 +- .../src/cpp/FileWatcherManager.cpp | 164 +++++++++--------- .../interpreter/src/cpp/MacroFunctionDef.cpp | 2 +- .../interpreter/src/cpp/PathFuncManager.cpp | 16 ++ .../src/cpp/UpdatePathListener.hpp | 68 ++++++++ .../src/include/FileWatcherManager.hpp | 14 +- .../src/include/PathFuncManager.hpp | 3 + modules/mex/functions/mex.m | 2 - .../profiler/builtin/cpp/profsaveBuiltin.cpp | 2 +- modules/profiler/src/cpp/HtmlExporter.cpp | 2 +- modules/profiler/src/cpp/HtmlExporter.hpp | 2 +- 14 files changed, 194 insertions(+), 90 deletions(-) create mode 100644 modules/interpreter/src/cpp/UpdatePathListener.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dbe3b36a7..09e8008c32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ - allows .m file empty to be called. +- [#477](http://github.com/Nelson-numerical-software/nelson/issues/477): update files watcher. + ## Bug Fixes: - [#480](http://github.com/Nelson-numerical-software/nelson/issues/480): publisher name updated for windows installer. diff --git a/modules/interpreter/src/c/nlsInterpreter.vcxproj b/modules/interpreter/src/c/nlsInterpreter.vcxproj index d2989519dc..2ea926f03d 100644 --- a/modules/interpreter/src/c/nlsInterpreter.vcxproj +++ b/modules/interpreter/src/c/nlsInterpreter.vcxproj @@ -325,6 +325,7 @@ + diff --git a/modules/interpreter/src/c/nlsInterpreter.vcxproj.filters b/modules/interpreter/src/c/nlsInterpreter.vcxproj.filters index d4339476de..b82665ab9d 100644 --- a/modules/interpreter/src/c/nlsInterpreter.vcxproj.filters +++ b/modules/interpreter/src/c/nlsInterpreter.vcxproj.filters @@ -376,6 +376,9 @@ Header Files + + Header Files + diff --git a/modules/interpreter/src/cpp/Evaluator.cpp b/modules/interpreter/src/cpp/Evaluator.cpp index f818f86b82..5bd086013b 100644 --- a/modules/interpreter/src/cpp/Evaluator.cpp +++ b/modules/interpreter/src/cpp/Evaluator.cpp @@ -127,7 +127,7 @@ class endData ArrayOf endArray; int index = 0; size_t count = 0; - endData(ArrayOf p, int ndx, size_t cnt) : endArray(p), index(ndx), count(cnt) { } + endData(ArrayOf p, int ndx, size_t cnt) : endArray(p), index(ndx), count(cnt) {} ~endData() = default; ; }; @@ -4200,7 +4200,6 @@ Evaluator::evalCLI() { while (1) { if (!bpActive) { - FileWatcherManager::getInstance()->update(); clearStacks(); } std::wstring commandLine; diff --git a/modules/interpreter/src/cpp/FileWatcherManager.cpp b/modules/interpreter/src/cpp/FileWatcherManager.cpp index 8f869d793c..9b4e0215ba 100644 --- a/modules/interpreter/src/cpp/FileWatcherManager.cpp +++ b/modules/interpreter/src/cpp/FileWatcherManager.cpp @@ -28,82 +28,36 @@ #include "FileWatcherManager.hpp" #include "PathFuncManager.hpp" #include "characters_encoding.hpp" -#include "MxGetExtension.hpp" +#include "UpdatePathListener.hpp" //============================================================================= namespace Nelson { //============================================================================= -class UpdatePathListener : public FW::FileWatchListener -{ -public: - UpdatePathListener() = default; - void - handleFileAction(WatchID watchid, const FW::String& dir, const FW::String& filename, - FW::Action action) override - { - switch (action) { - case FW::Action::Add: { - boost::filesystem::path pf = boost::filesystem::path(filename); - std::wstring file_extension = pf.extension().generic_wstring(); - if (file_extension == L".m" || file_extension == L"." + getMexExtension()) { - boost::filesystem::path parent_dir = boost::filesystem::path(dir); - PathFuncManager::getInstance()->rehash(parent_dir.generic_wstring()); - /* - #ifdef _MSC_VER - printf("Added: %ls\n", filename.c_str()); - #else - printf("Added: %s\n", filename.c_str()); - #endif - */ - } - } break; - case FW::Action::Delete: { - boost::filesystem::path pf = boost::filesystem::path(filename); - std::wstring file_extension = pf.extension().generic_wstring(); - if (file_extension == L".m" || file_extension == L"." + getMexExtension()) { - boost::filesystem::path parent_dir = boost::filesystem::path(dir); - PathFuncManager::getInstance()->rehash(parent_dir.generic_wstring()); - /* - #ifdef _MSC_VER - printf("Delete: %ls\n", filename.c_str()); - #else - printf("Delete: %s\n", filename.c_str()); - #endif - */ - } - } break; - case FW::Action::Modified: - boost::filesystem::path pf = boost::filesystem::path(filename); - std::wstring file_extension = pf.extension().generic_wstring(); - if (file_extension == L".m" || file_extension == L"." + getMexExtension()) { - /* - #ifdef _MSC_VER - printf("Modified: %ls\n", filename.c_str()); - #else - printf("Modified: %s\n", filename.c_str()); - #endif - */ - } - break; - } - } -}; -//============================================================================= FileWatcherManager* FileWatcherManager::m_pInstance = nullptr; //============================================================================= -FileWatcherManager::FileWatcherManager() +static std::wstring +uniformizePath(const std::wstring& directory) { - auto* tmp = new FW::FileWatcher(); - fileWatcher = (void*)tmp; + std::wstring uniformPath = directory; + if ((directory.back() == L'/') || (directory.back() == L'\\')) { + uniformPath.pop_back(); + } + boost::filesystem::path path(uniformPath); + path = boost::filesystem::absolute(path); + uniformPath = path.generic_wstring(); +#ifdef _MSC_VER + uniformPath = uniformPath + L"\\"; +#else + uniformPath = uniformPath + L"/"; +#endif + return uniformPath; } //============================================================================= -void -FileWatcherManager::release() +FileWatcherManager::FileWatcherManager() { - auto* ptr = static_cast(fileWatcher); - if (ptr != nullptr) { - delete ptr; - fileWatcher = nullptr; - } + UpdatePathListener* _fileListener = new UpdatePathListener(); + fileListener = static_cast(_fileListener); + FW::FileWatcher* _fileWatcher = new FW::FileWatcher(); + fileWatcher = static_cast(_fileWatcher); } //============================================================================= FileWatcherManager* @@ -118,28 +72,41 @@ FileWatcherManager::getInstance() void FileWatcherManager::addWatch(const std::wstring& directory) { - auto* watcher = new UpdatePathListener(); - WatchID id = -1; - try { + std::wstring uniformizedPath = uniformizePath(directory); + std::map>::iterator it = watchIDsMap.find(uniformizedPath); + if (it == watchIDsMap.end()) { + UpdatePathListener* _fileListener = static_cast(fileListener); + WatchID id; + try { #ifdef _MSC_VER - id = (static_cast(fileWatcher))->addWatch(directory, watcher); + id = (static_cast(fileWatcher))->addWatch(directory, _fileListener); #else - id = ((FW::FileWatcher*)fileWatcher)->addWatch(wstring_to_utf8(directory), watcher); + id = ((FW::FileWatcher*)fileWatcher) + ->addWatch(wstring_to_utf8(directory), _fileListener); #endif - } catch (const FW::FWException&) { + } catch (const FW::FWException&) { + id = -1; + } + if (id != -1) { + watchIDsMap.emplace(uniformizedPath, std::make_pair(id, 1)); + } + } else { + it->second.second++; } } //============================================================================= void FileWatcherManager::removeWatch(const std::wstring& directory) { - try { -#ifdef _MSC_VER - (static_cast(fileWatcher))->removeWatch(directory); -#else - ((FW::FileWatcher*)fileWatcher)->removeWatch(wstring_to_utf8(directory)); -#endif - } catch (const FW::FWException&) { + std::wstring uniformizedPath = uniformizePath(directory); + std::map>::iterator it = watchIDsMap.find(uniformizedPath); + if (it != watchIDsMap.end()) { + if (it->second.second == 1) { + ((FW::FileWatcher*)fileWatcher)->removeWatch(it->second.first); + watchIDsMap.erase(it); + } else { + it->second.second--; + } } } //============================================================================= @@ -152,5 +119,40 @@ FileWatcherManager::update() } } //============================================================================= -} // namespace Nelson +void +FileWatcherManager::release() +{ + UpdatePathListener* _fileListener = static_cast(fileListener); + if (_fileListener) { + delete _fileListener; + _fileListener = nullptr; + fileListener = nullptr; + } + FW::FileWatcher* _fileWatcher = static_cast(fileWatcher); + if (_fileWatcher != nullptr) { + delete _fileWatcher; + _fileWatcher = nullptr; + fileWatcher = nullptr; + } + pathsToRefresh.clear(); + watchIDsMap.clear(); +} +//============================================================================= +void +FileWatcherManager::addPathToRefreshList(const std::wstring& directory) +{ + pathsToRefresh.push_back(directory); +} +//============================================================================= +wstringVector +FileWatcherManager::getPathToRefresh(bool withClear) +{ + wstringVector paths = pathsToRefresh; + if (withClear) { + pathsToRefresh.clear(); + } + return paths; +} +//============================================================================= +} //============================================================================= diff --git a/modules/interpreter/src/cpp/MacroFunctionDef.cpp b/modules/interpreter/src/cpp/MacroFunctionDef.cpp index aa8c74fff4..018b3b4677 100644 --- a/modules/interpreter/src/cpp/MacroFunctionDef.cpp +++ b/modules/interpreter/src/cpp/MacroFunctionDef.cpp @@ -439,7 +439,7 @@ MacroFunctionDef::updateCode() this->returnVals = macroFunctionDef->returnVals; this->ptrAstCodeAsVector = macroFunctionDef->ptrAstCodeAsVector; this->setName(macroFunctionDef->getName()); - } + } } else { this->code = getParsedScriptBlock(); this->arguments.clear(); diff --git a/modules/interpreter/src/cpp/PathFuncManager.cpp b/modules/interpreter/src/cpp/PathFuncManager.cpp index 3456e783db..38b032ada6 100644 --- a/modules/interpreter/src/cpp/PathFuncManager.cpp +++ b/modules/interpreter/src/cpp/PathFuncManager.cpp @@ -172,10 +172,21 @@ PathFuncManager::find(const std::string& name, FunctionDefPtr& ptr) return false; } //============================================================================= +void +PathFuncManager::fileWatcherUpdate() +{ + FileWatcherManager::getInstance()->update(); + wstringVector paths = FileWatcherManager::getInstance()->getPathToRefresh(true); + for (auto p : paths) { + rehash(p); + } +} +//============================================================================= bool PathFuncManager::find(const std::wstring& functionName, FileFunction** ff) { bool res = false; + fileWatcherUpdate(); if (_currentPath != nullptr) { res = _currentPath->findFuncName(functionName, ff); if (res) { @@ -204,6 +215,7 @@ PathFuncManager::find(const std::wstring& functionName, FileFunction** ff) bool PathFuncManager::find(const std::wstring& functionName, std::wstring& filename) { + fileWatcherUpdate(); if (_currentPath != nullptr) { if (_currentPath->findFuncName(functionName, filename)) { return true; @@ -228,6 +240,7 @@ bool PathFuncManager::find(const std::wstring& functionName, wstringVector& filesname) { filesname.clear(); + fileWatcherUpdate(); std::wstring filename; if (_currentPath != nullptr) { if (_currentPath->findFuncName(functionName, filename)) { @@ -333,6 +346,9 @@ bool PathFuncManager::setCurrentUserPath(const std::wstring& path) { if (_currentPath != nullptr) { + if (isSamePath(path, _currentPath->getPath())) { + return true; + } delete _currentPath; } _currentPath = new PathFunc(path); diff --git a/modules/interpreter/src/cpp/UpdatePathListener.hpp b/modules/interpreter/src/cpp/UpdatePathListener.hpp new file mode 100644 index 0000000000..cb9aea81b9 --- /dev/null +++ b/modules/interpreter/src/cpp/UpdatePathListener.hpp @@ -0,0 +1,68 @@ +//============================================================================= +// Copyright (c) 2016-present Allan CORNET (Nelson) +//============================================================================= +// This file is part of the Nelson. +//============================================================================= +// LICENCE_BLOCK_BEGIN +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// Alternatively, you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program. If not, see . +// LICENCE_BLOCK_END +//============================================================================= +#pragma once +//============================================================================= +#include +#include +#include +#include "FileWatcherManager.hpp" +#include "MxGetExtension.hpp" +//============================================================================= +class UpdatePathListener : public FW::FileWatchListener +{ +private: + //============================================================================= + void + appendIfNelsonFile(const FW::String& dir, const FW::String& filename) + { + boost::filesystem::path pf = boost::filesystem::path(filename); + std::wstring file_extension = pf.extension().generic_wstring(); + if (file_extension == L".m" || file_extension == L"." + Nelson::getMexExtension()) { + boost::filesystem::path parent_dir = boost::filesystem::path(dir); + Nelson::FileWatcherManager::getInstance()->addPathToRefreshList( + parent_dir.generic_wstring()); + } + } + //============================================================================= +public: + UpdatePathListener() = default; + void + handleFileAction(WatchID watchid, const FW::String& dir, const FW::String& filename, + FW::Action action) override + { + switch (action) { + case FW::Action::Add: { + appendIfNelsonFile(dir, filename); + } break; + case FW::Action::Delete: { + appendIfNelsonFile(dir, filename); + } break; + case FW::Action::Modified: { + } break; + } + } +}; +//============================================================================= diff --git a/modules/interpreter/src/include/FileWatcherManager.hpp b/modules/interpreter/src/include/FileWatcherManager.hpp index 21bd861c64..b119b4e136 100644 --- a/modules/interpreter/src/include/FileWatcherManager.hpp +++ b/modules/interpreter/src/include/FileWatcherManager.hpp @@ -26,11 +26,15 @@ #pragma once //============================================================================= #include +#include +#include +#include "Types.hpp" //============================================================================= namespace Nelson { //============================================================================= class FileWatcherManager { + //============================================================================= public: static FileWatcherManager* getInstance(); @@ -42,11 +46,19 @@ class FileWatcherManager update(); void release(); - + void + addPathToRefreshList(const std::wstring& directory); + wstringVector + getPathToRefresh(bool withClear = true); + //============================================================================= private: FileWatcherManager(); static FileWatcherManager* m_pInstance; void* fileWatcher; + void* fileListener; + std::map> watchIDsMap; + wstringVector pathsToRefresh; + //============================================================================= }; //============================================================================= } // namespace Nelson diff --git a/modules/interpreter/src/include/PathFuncManager.hpp b/modules/interpreter/src/include/PathFuncManager.hpp index 9909781876..991d536f4b 100644 --- a/modules/interpreter/src/include/PathFuncManager.hpp +++ b/modules/interpreter/src/include/PathFuncManager.hpp @@ -57,6 +57,9 @@ class NLSINTERPRETER_IMPEXP PathFuncManager FunctionDef* findAndProcessFile(const std::string& name); + void + fileWatcherUpdate(); + void userpathCompute(); std::wstring diff --git a/modules/mex/functions/mex.m b/modules/mex/functions/mex.m index ff12e181a7..dedcb04d1b 100644 --- a/modules/mex/functions/mex.m +++ b/modules/mex/functions/mex.m @@ -123,8 +123,6 @@ function mex(varargin) fullDestinationLibraryName = [destinationPath, functionName, '.lib']; rmfile(fullDestinationLibraryName) end - cd(destinationPath) - cd(pwd()) end end %============================================================================= diff --git a/modules/profiler/builtin/cpp/profsaveBuiltin.cpp b/modules/profiler/builtin/cpp/profsaveBuiltin.cpp index 6dc28ef101..6a70bc7925 100644 --- a/modules/profiler/builtin/cpp/profsaveBuiltin.cpp +++ b/modules/profiler/builtin/cpp/profsaveBuiltin.cpp @@ -37,7 +37,7 @@ using namespace Nelson; // profsave(profinfo, dirname) //============================================================================= static std::wstring -filePartPath(const std::wstring &dirname) +filePartPath(const std::wstring& dirname) { boost::filesystem::path pathToSplit = dirname; std::wstring path; diff --git a/modules/profiler/src/cpp/HtmlExporter.cpp b/modules/profiler/src/cpp/HtmlExporter.cpp index daa5f74120..8d308aaf85 100644 --- a/modules/profiler/src/cpp/HtmlExporter.cpp +++ b/modules/profiler/src/cpp/HtmlExporter.cpp @@ -322,7 +322,7 @@ sectionFunctionListing(std::ofstream& file, const stringVector& functionContent, //============================================================================= void generateProfileFileHtml(const std::wstring& srcFilename, const stringVector& functionContent, - const std::vector> &fiveSlowerLines, + const std::vector>& fiveSlowerLines, std::tuple coverage, std::vector> lineInfo, int nbCalls, double totalTime, const std::wstring& htmlFilename) diff --git a/modules/profiler/src/cpp/HtmlExporter.hpp b/modules/profiler/src/cpp/HtmlExporter.hpp index 21815b627e..e55a611b41 100644 --- a/modules/profiler/src/cpp/HtmlExporter.hpp +++ b/modules/profiler/src/cpp/HtmlExporter.hpp @@ -41,7 +41,7 @@ copyHtmlDependencies( //============================================================================= void generateProfileFileHtml(const std::wstring& srcFilename, const stringVector& functionContent, - const std::vector> &fiveSlowerLines, + const std::vector>& fiveSlowerLines, std::tuple coverage, std::vector> lineInfo, int nbCalls, double totalTime, const std::wstring& htmlFilename);