From a33a8292a4a8984ed08bf0d2f0ed374762e499b9 Mon Sep 17 00:00:00 2001 From: John Beard Date: Mon, 10 Dec 2018 10:56:28 +0000 Subject: [PATCH] Run-time config for advanced options This can be used for "advanced" options which are for developers to use for feature-flags and other configuration. Run time config has some advantages over preprocessor defines: * Can be changed without recompilation * Sensitive to XDG_CONFIG_DIR, so flipping configs is easy * Better compiler coverage (less conditionally compiled code means less chance to break a different configuration). Also better analysis coverage. * Type safe config params * Centralised documentation: it's in doxygen, in one place No advanced config should be required by a general users. If a general user does use one of these configs, it's probably because: * There is a bug and one of these configs is a workaround * A config in here is generally useful and should be moved into the relevant application config and given UI. For now, the config is read-only, and is read from the "kicad_advanced" config file in the normal config dir. --- Documentation/development/testing.md | 13 ++- common/CMakeLists.txt | 1 + common/advanced_config.cpp | 161 +++++++++++++++++++++++++++ include/advanced_config.h | 85 ++++++++++++++ 4 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 common/advanced_config.cpp create mode 100644 include/advanced_config.h diff --git a/Documentation/development/testing.md b/Documentation/development/testing.md index e0c3c04aed..6030d986de 100644 --- a/Documentation/development/testing.md +++ b/Documentation/development/testing.md @@ -259,9 +259,20 @@ Some available masks: * `KICAD_GEDA_PLUGIN` * `KICAD_PCB_PLUGIN` +# Advanced configuration + +There are some advance configuration options, which are mostly used for +development or testing purposes. + +To set these options, you can create the file `kicad_advanced` and set the keys +as desired (the [advanced config documentation][] for a current list. You should +never need to set these keys for normal usage - if you do, that's a bug. + [CTest]: https://cmake.org/cmake/help/latest/module/CTest.html [Boost Unit Test framework]: https://www.boost.org/doc/libs/1_68_0/libs/test/doc/html/index.html [boost-test-functions]: https://www.boost.org/doc/libs/1_68_0/libs/test/doc/html/boost_test/utf_reference/testing_tool_ref.html [AFL fuzzing tool]: http://lcamtuf.coredump.cx/afl/ -[trace mask documentation]: http://docs.kicad-pcb.org/doxygen/group__trace__env__vars.html \ No newline at end of file +[trace mask documentation]: http://docs.kicad-pcb.org/doxygen/group__trace__env__vars.html +[trace mask documentation]: http://docs.kicad-pcb.org/doxygen/group__trace__env__vars.html +[advanced config documentation]: http://docs.kicad-pcb.org/doxygen/namespaceAC__KEYS.html \ No newline at end of file diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 569543a870..1ef0850b62 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -269,6 +269,7 @@ set( COMMON_SRCS ${COMMON_PAGE_LAYOUT_SRCS} ${COMMON_PREVIEW_ITEMS_SRCS} ${PLOTTERS_CONTROL_SRCS} + advanced_config.cpp base_struct.cpp bezier_curves.cpp bin_mod.cpp diff --git a/common/advanced_config.cpp b/common/advanced_config.cpp new file mode 100644 index 0000000000..bf69424f23 --- /dev/null +++ b/common/advanced_config.cpp @@ -0,0 +1,161 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include +#include + +#include +#include +#include + +/* + * Flag to enable advanced config debugging + * + * Use "KICAD_ADVANCED_CONFIG" to enable. + * + * @ingroup trace_env_vars + */ +static const wxChar AdvancedConfigMask[] = wxT( "KICAD_ADVANCED_CONFIG" ); + +/** + * List of known keys for advanced configuration options. + * + * Set these options in the file `kicad_advanced` in the + * KiCad config directory. + */ +namespace AC_KEYS +{ +} // namespace KEYS + + +/* + * Get a simple string for common parameters. + * + * This isn't exhaustive, but it covers most common types that might be + * used in the advance config + */ +wxString dumpParamCfg( const PARAM_CFG_BASE& aParam ) +{ + wxString s = aParam.m_Ident + ": "; + + /* + * This implementation is rather simplistic, but it is + * effective enough for simple uses. A better implementation would be + * some kind of visitor, but that's somewhat more work. + */ + switch( aParam.m_Type ) + { + case paramcfg_id::PARAM_INT: + case paramcfg_id::PARAM_INT_WITH_SCALE: + s << *static_cast( aParam ).m_Pt_param; + break; + case paramcfg_id::PARAM_DOUBLE: + s << *static_cast( aParam ).m_Pt_param; + break; + case paramcfg_id::PARAM_WXSTRING: + s << *static_cast( aParam ).m_Pt_param; + break; + case paramcfg_id::PARAM_FILENAME: + s << *static_cast( aParam ).m_Pt_param; + break; + case paramcfg_id::PARAM_BOOL: + s << ( *static_cast( aParam ).m_Pt_param ? "true" : "false" ); + break; + default: s << "Unsupported PARAM_CFG variant: " << aParam.m_Type; + } + + return s; +} + + +/** + * Dump the configs in the given array to trace. + */ +static void dumpCfg( const PARAM_CFG_ARRAY& aArray ) +{ + // only dump if we need to + if( !wxLog::IsAllowedTraceMask( AdvancedConfigMask ) ) + return; + + for( const auto& param : aArray ) + { + wxLogTrace( AdvancedConfigMask, dumpParamCfg( param ) ); + } +} + + +/** + * Get the filename for the advanced config file + * + * The user must check the file exists if they care. + */ +static wxFileName getAdvancedCfgFilename() +{ + const static wxString cfg_filename{ "kicad_advanced" }; + return wxFileName( GetKicadConfigPath(), cfg_filename ); +} + + +ADVANCED_CFG::ADVANCED_CFG() +{ + wxLogTrace( AdvancedConfigMask, "Init advanced config" ); + loadFromConfigFile(); +} + + +const ADVANCED_CFG& ADVANCED_CFG::GetCfg() +{ + static ADVANCED_CFG instance; + return instance; +} + + +void ADVANCED_CFG::loadFromConfigFile() +{ + const auto k_advanced = getAdvancedCfgFilename(); + + if( !k_advanced.FileExists() ) + { + wxLogTrace( AdvancedConfigMask, "File does not exist %s", k_advanced.GetFullPath() ); + return; + } + + wxLogTrace( AdvancedConfigMask, "Loading advanced config from: %s", k_advanced.GetFullPath() ); + + wxFileConfig file_cfg( "", "", k_advanced.GetFullPath() ); + loadSettings( file_cfg ); +} + + +void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg ) +{ + PARAM_CFG_ARRAY configParams; + + // Add configs here + + wxConfigLoadSetups( &aCfg, configParams ); + + dumpCfg( configParams ); +} \ No newline at end of file diff --git a/include/advanced_config.h b/include/advanced_config.h new file mode 100644 index 0000000000..07681722e9 --- /dev/null +++ b/include/advanced_config.h @@ -0,0 +1,85 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef ADVANCED_CFG__H +#define ADVANCED_CFG__H + +class wxConfigBase; + +/** + * Class containing "advanced" configuration options. + * + * Options set here are for developer or advanced users only. If a general user + * needs to set one of these for normal KiCad use, either: + * * They are working around some bug that should be fixed, or + * * The parameter they are setting is of general interest and should be in the + * main application config, with UI provided. + * + * Options in this class are, in general, preferable to #defines, as they + * allow more flexible configuration by developers, and don't hide code from + * the compiler on other configurations, which can result in broken builds. + * + * Never use advanced configs in an untestable way. If a function depends on + * advanced config such that you cannot test it without changing the config, + * "lift" the config to a higher level and make pass it as parameter of the code + * under test. The tests can pass their own values as needed. + * + * This also applies to code that does not depend on "common" - it cannot + * use this class, so you must pass configuration in as proper parameters. + * + * Sometimes you can just use values directly, and sometimes helper functions + * might be provided to allow extra logic (for example when a advanced config + * applies only on certain platforms). + * + * For more information on what config keys set these parameters in the + * config files, and why you might want to set them, see #AC_KEYS + * + */ +class ADVANCED_CFG +{ +public: + /** + * Get the singleton instance's config, which is shared by all + * consumers of advanced config. + * + * This configuration is read-only - to set options, users should + * add the parameters to their config files at ~/.config/kicad/advanced, or the + * platform equivalent. + */ + static const ADVANCED_CFG& GetCfg(); + +private: + ADVANCED_CFG(); + + /** + * Load the config from the normal config file + */ + void loadFromConfigFile(); + + /* + * Load config from the given config base + */ + void loadSettings( wxConfigBase& aCfg ); +}; + +#endif // ADVANCED_CFG__H