From b6abb83b6e36ee9735a5c34b33e38c878aa233fb Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 11 Dec 2014 03:36:51 +0000 Subject: Use time based logic controlled from OptionsSource to determine if configurations need reloading and if loading was successful --- project2/cli/claOptions.cpp | 9 ++- project2/cli/claOptions.h | 4 +- project2/common/optionsSource.cpp | 21 ++++--- project2/common/optionsSource.h | 6 +- project2/files/.ycm_extra_conf.py | 117 ++++++++++++++++++++++++++++++++++++++ project2/files/optionsSource.cpp | 37 ++++++------ project2/files/optionsSource.h | 13 +++-- project2/ut/testOptionsSource.cpp | 7 ++- project2/ut/testOptionsSource.h | 3 +- 9 files changed, 171 insertions(+), 46 deletions(-) create mode 100644 project2/files/.ycm_extra_conf.py diff --git a/project2/cli/claOptions.cpp b/project2/cli/claOptions.cpp index b1e1250..da6121d 100644 --- a/project2/cli/claOptions.cpp +++ b/project2/cli/claOptions.cpp @@ -12,7 +12,7 @@ CommandLineArguments::CommandLineArguments(int c, const char * const * v, const argc(c), argv(v), others(o), - loadedAt(0) + createdAt(boost::posix_time::microsec_clock::universal_time()) { } @@ -76,12 +76,11 @@ CommandLineArguments::loadInto(const ConfigConsumer & consume, const Options::Cu others(argv[x]); } } - time(&loadedAt); } -bool -CommandLineArguments::needReload() const +boost::posix_time::ptime +CommandLineArguments::modifiedTime() const { - return !loadedAt; + return createdAt; } diff --git a/project2/cli/claOptions.h b/project2/cli/claOptions.h index c669004..3f13b4b 100644 --- a/project2/cli/claOptions.h +++ b/project2/cli/claOptions.h @@ -8,13 +8,13 @@ class CommandLineArguments : public OptionsSource { typedef boost::function Others; CommandLineArguments(int c, const char * const * v, const Others &); void loadInto(const ConfigConsumer & consume, const Options::CurrentPlatform & platform) const; - bool needReload() const; + boost::posix_time::ptime modifiedTime() const override; private: const int argc; const char * const * argv; const Others others; - mutable time_t loadedAt; + const boost::posix_time::ptime createdAt; }; #endif diff --git a/project2/common/optionsSource.cpp b/project2/common/optionsSource.cpp index 85aebb1..1665557 100644 --- a/project2/common/optionsSource.cpp +++ b/project2/common/optionsSource.cpp @@ -20,11 +20,14 @@ class DefaultConfigConsumer : public ConfigConsumer { } }; + +boost::posix_time::ptime OptionsSource::loadedTime = boost::posix_time::special_values::neg_infin; + void OptionsSource::loadSources(const Options::CurrentPlatform & platform) { const auto & configs = InstanceSet::GetAll(); - if (std::find_if(configs.begin(), configs.end(), boost::bind(&OptionsSource::needReload, _1)) != configs.end()) { + if (std::find_if(configs.begin(), configs.end(), [](const OptionsSourcePtr & c) { return c->modifiedTime() > loadedTime; }) != configs.end()) { InstanceSet::OnAll(boost::bind(&Options::reset, _1)); DefaultConfigConsumer dcc; @@ -39,20 +42,22 @@ OptionsSource::loadSources(const Options::CurrentPlatform & platform) } Plugable::onAllComponents(boost::bind(&ComponentLoader::onConfigLoad, _1)); - Logger()->message(LOG_DEBUG, "Loaded configuration"); + loadedTime = boost::posix_time::microsec_clock::universal_time(); + Logger()->messagebf(LOG_DEBUG, "Loaded configuration at %s", loadedTime); } } void OptionsSource::loadSource(const Options::CurrentPlatform & platform, OptionsSourcePtr opts) { - InstanceSet::OnAll(boost::bind(&Options::reset, _1)); + InstanceSet::OnAll(boost::bind(&Options::reset, _1)); - DefaultConfigConsumer dcc; - opts->loadInto(dcc, platform); - Plugable::onAllComponents(boost::bind(&ComponentLoader::onConfigLoad, _1)); - - Logger()->message(LOG_DEBUG, "Loaded configuration"); + DefaultConfigConsumer dcc; + opts->loadInto(dcc, platform); + Plugable::onAllComponents(boost::bind(&ComponentLoader::onConfigLoad, _1)); + + loadedTime = boost::posix_time::microsec_clock::universal_time(); + Logger()->messagebf(LOG_DEBUG, "Loaded configuration at %s", loadedTime); } INSTANTIATESTORE(std::string, OptionsSource); diff --git a/project2/common/optionsSource.h b/project2/common/optionsSource.h index 6cfbce9..4e0792b 100644 --- a/project2/common/optionsSource.h +++ b/project2/common/optionsSource.h @@ -2,6 +2,7 @@ #define OPTIONSSOURCE_H #include +#include #include #include #include "scriptLoader.h" @@ -20,10 +21,13 @@ typedef boost::shared_ptr OptionsSourcePtr; class OptionsSource { public: virtual void loadInto(const ConfigConsumer &, const Options::CurrentPlatform & platform) const = 0; - virtual bool needReload() const = 0; + virtual boost::posix_time::ptime modifiedTime() const = 0; static void loadSources(const Options::CurrentPlatform & platform); static void loadSource(const Options::CurrentPlatform & platform, OptionsSourcePtr opts); + + private: + static boost::posix_time::ptime loadedTime; }; typedef PluginsSameBase OptionsSources; diff --git a/project2/files/.ycm_extra_conf.py b/project2/files/.ycm_extra_conf.py new file mode 100644 index 0000000..e4f4c84 --- /dev/null +++ b/project2/files/.ycm_extra_conf.py @@ -0,0 +1,117 @@ +import os +import ycm_core + +flags = [ +'-Wall', +'-Wextra', +'-Werror', +'-Wc++98-compat', +'-Wno-long-long', +'-Wno-variadic-macros', +'-fexceptions', +'-DNDEBUG', +'-std=c++11', +'-x', +'c++', +'-I', +'.', +'-I', +'../common', +'-I', +'../lib', +'-isystem', +'/usr/include', +'-isystem', +'/usr/include/glibmm-2.4', +] + +# Set this to the absolute path to the folder (NOT the file!) containing the +# compile_commands.json file to use that instead of 'flags'. See here for +# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html +# +# Most projects will NOT need to set this to anything; you can just change the +# 'flags' list of compilation flags. Notice that YCM itself uses that approach. +compilation_database_folder = '' + +if os.path.exists( compilation_database_folder ): + database = ycm_core.CompilationDatabase( compilation_database_folder ) +else: + database = None + +SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.m', '.mm' ] + +def DirectoryOfThisScript(): + return os.path.dirname( os.path.abspath( __file__ ) ) + + +def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): + if not working_directory: + return list( flags ) + new_flags = [] + make_next_absolute = False + path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] + for flag in flags: + new_flag = flag + + if make_next_absolute: + make_next_absolute = False + if not flag.startswith( '/' ): + new_flag = os.path.join( working_directory, flag ) + + for path_flag in path_flags: + if flag == path_flag: + make_next_absolute = True + break + + if flag.startswith( path_flag ): + path = flag[ len( path_flag ): ] + new_flag = path_flag + os.path.join( working_directory, path ) + break + + if new_flag: + new_flags.append( new_flag ) + return new_flags + + +def IsHeaderFile( filename ): + extension = os.path.splitext( filename )[ 1 ] + return extension in [ '.h', '.hxx', '.hpp', '.hh' ] + + +def GetCompilationInfoForFile( filename ): + # The compilation_commands.json file generated by CMake does not have entries + # for header files. So we do our best by asking the db for flags for a + # corresponding source file, if any. If one exists, the flags for that file + # should be good enough. + if IsHeaderFile( filename ): + basename = os.path.splitext( filename )[ 0 ] + for extension in SOURCE_EXTENSIONS: + replacement_file = basename + extension + if os.path.exists( replacement_file ): + compilation_info = database.GetCompilationInfoForFile( + replacement_file ) + if compilation_info.compiler_flags_: + return compilation_info + return None + return database.GetCompilationInfoForFile( filename ) + + +def FlagsForFile( filename, **kwargs ): + if database: + # Bear in mind that compilation_info.compiler_flags_ does NOT return a + # python list, but a "list-like" StringVec object + compilation_info = GetCompilationInfoForFile( filename ) + if not compilation_info: + return None + + final_flags = MakeRelativePathsInFlagsAbsolute( + compilation_info.compiler_flags_, + compilation_info.compiler_working_dir_ ) + else: + relative_to = DirectoryOfThisScript() + final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) + + return { + 'flags': final_flags, + 'do_cache': True + } diff --git a/project2/files/optionsSource.cpp b/project2/files/optionsSource.cpp index bb8c549..ed78be4 100644 --- a/project2/files/optionsSource.cpp +++ b/project2/files/optionsSource.cpp @@ -1,20 +1,20 @@ #include -#include +#include #include "optionsSource.h" #include #include #include -FileOptions::FileOptions(const Glib::ustring & f) : - file(f), - loadedAt(0) +FileOptions::FileOptions(const boost::filesystem::path & f) : + file(boost::filesystem::current_path() / f) { } void -FileOptions::loadInto(const ConfigConsumer & consume, const Options::CurrentPlatform & platform) const { - try { - Glib::RefPtr cfg = Glib::IOChannel::create_from_file(file, "r"); +FileOptions::loadInto(const ConfigConsumer & consume, const Options::CurrentPlatform & platform) const +{ + if (boost::filesystem::exists(file)) { + Glib::RefPtr cfg = Glib::IOChannel::create_from_file(file.string(), "r"); Glib::ustring line; Glib::ustring prefix; while (cfg->read_line(line) != Glib::IO_STATUS_EOF) { @@ -50,23 +50,18 @@ FileOptions::loadInto(const ConfigConsumer & consume, const Options::CurrentPlat break; } } - struct stat st; - if (stat(file.c_str(), &st) == 0) { - loadedAt = st.st_mtime; - } - } - catch (const Glib::FileError &) { } } -bool -FileOptions::needReload() const +boost::posix_time::ptime +FileOptions::modifiedTime() const { - struct stat st; - if (stat(file.c_str(), &st) != 0) { - return true; - } - return (loadedAt != st.st_mtime); + return boost::posix_time::from_time_t( + boost::filesystem::exists(file) ? + std::max( + boost::filesystem::last_write_time(file), + boost::filesystem::last_write_time(file.parent_path())) : + boost::filesystem::last_write_time(file.parent_path())); } FileOptions::ExtraFileOptions FileOptions::extraFileOptions; @@ -77,7 +72,7 @@ DECLARE_OPTIONSSOURCE("Z_configfile", new FileOptions(".p2config")) DECLARE_OPTIONS(FileOptions, "File Options options") ("file.options.read", Options::functions( [](const VariableType & vt) { - auto fo = new FileOptions(vt); + auto fo = new FileOptions(vt.as()); extraFileOptions[vt] = boost::shared_ptr(fo); OptionsSources::Add(vt, fo); }, diff --git a/project2/files/optionsSource.h b/project2/files/optionsSource.h index 6f25459..a6d1cd1 100644 --- a/project2/files/optionsSource.h +++ b/project2/files/optionsSource.h @@ -3,20 +3,23 @@ #include "../common/optionsSource.h" #include "../common/options.h" +#include + +class FileOptions; +typedef boost::shared_ptr FileOptionsPtr; class FileOptions : public OptionsSource { public: - FileOptions(const Glib::ustring & file); + FileOptions(const boost::filesystem::path & file); void loadInto(const ConfigConsumer & consume, const Options::CurrentPlatform & platform) const; - bool needReload() const; + boost::posix_time::ptime modifiedTime() const override; INITOPTIONS; private: - const Glib::ustring file; - mutable time_t loadedAt; + const boost::filesystem::path file; - typedef std::map> ExtraFileOptions; + typedef std::map ExtraFileOptions; static ExtraFileOptions extraFileOptions; }; diff --git a/project2/ut/testOptionsSource.cpp b/project2/ut/testOptionsSource.cpp index 59dc882..41a05fd 100644 --- a/project2/ut/testOptionsSource.cpp +++ b/project2/ut/testOptionsSource.cpp @@ -3,6 +3,7 @@ const Glib::ustring testPlatform; TestOptionsSource::TestOptionsSource(const Opts & o) : + createdAt(boost::posix_time::microsec_clock::universal_time()), opts(o) { } @@ -15,10 +16,10 @@ TestOptionsSource::loadInto(const ConfigConsumer & consume, const Options::Curre } } -bool -TestOptionsSource::needReload() const +boost::posix_time::ptime +TestOptionsSource::modifiedTime() const { - return true; + return createdAt; } void diff --git a/project2/ut/testOptionsSource.h b/project2/ut/testOptionsSource.h index 9bc2101..3d0e046 100644 --- a/project2/ut/testOptionsSource.h +++ b/project2/ut/testOptionsSource.h @@ -8,12 +8,13 @@ class TestOptionsSource : public OptionsSource { typedef std::list> Opts; void loadInto(const ConfigConsumer & consume, const Options::CurrentPlatform & platform) const override; - bool needReload() const override; + boost::posix_time::ptime modifiedTime() const override; static void LoadTestOptions(const Opts & o); private: TestOptionsSource(const Opts & o); + const boost::posix_time::ptime createdAt; const Opts opts; }; -- cgit v1.2.3