diff --git a/docs/faq.rst b/docs/faq.rst index e8f650d5..75ed3cfb 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -33,37 +33,6 @@ What is ``.pioenvs`` directory Please refer to :ref:`projectconf_pio_envs_dir`. -.. _faq_ldf: - -How works Library Dependency Finder (LDF) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Library Dependency Finder is a part of PlatformIO Library Build System. It -operates with the C/C++ source files and looks for ``#include <...>`` -directives. Also, LDF interprets C Preprocessor conditional macros -(``#if``, ``ifdef``, etc.). Library Dependency Finder starts -work from analyzing source files from :ref:`projectconf_pio_src_dir` by default. - -If project or library contains own ``dependencies`` list (see -:ref:`libjson_dependencies`), the LDF will not looking for dependencies in -the source code. The specified libraries will be built automatically without -check. - -There are different library storages where Library Dependency Finder looks for -dependencies. These storages/folders have priority. LDF operates in the next -order: - -1. :ref:`projectconf_lib_extra_dirs` -2. :ref:`projectconf_pio_lib_dir` -3. :ref:`projectconf_pio_home_dir`/lib - -Library Dependency Finder has a few controls from :ref:`projectconf`: - -* :ref:`projectconf_lib_ignore` -* :ref:`projectconf_lib_deep_search` -* :ref:`projectconf_lib_extra_dirs` -* :ref:`projectconf_lib_compat_mode` - Command completion in Terminal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/index.rst b/docs/index.rst index 2db1a873..3b95e020 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -119,6 +119,7 @@ Contents Quickstart User Guide + librarymanager/ldf librarymanager/config librarymanager/creating diff --git a/docs/librarymanager/ldf.rst b/docs/librarymanager/ldf.rst new file mode 100644 index 00000000..c3526436 --- /dev/null +++ b/docs/librarymanager/ldf.rst @@ -0,0 +1,171 @@ +.. Copyright 2014-present Ivan Kravets + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +.. _ldf: + +Library Dependency Finder (LDF) +=============================== + +.. versionadded:: 3.0 + +Library Dependency Finder is a core part of PlatformIO Build System that +operates with the C/C++ source files and looks for ``#include ...`` +directives. + +In spite of the fact that Library Dependency Finder is written in pure Python, +it interprets (emulates) :ref:`ldf_c_cond_syntax` (``#ifdef``, ``if``, ``defined``, +``else``, and ``elif``) without calling ``gcc -E``. This approach allows +significantly reduce total compilation time. + +Library Dependency Finder has controls that can be set up in :ref:`projectconf`: + +.. hlist:: + :columns: 3 + + * :ref:`projectconf_lib_extra_dirs` + * :ref:`projectconf_lib_force` + * :ref:`projectconf_lib_ignore` + * :ref:`projectconf_lib_compat_mode` + * :ref:`projectconf_lib_ldf_mode` + +----------- + +.. contents:: + +Storage +------- + +There are different storages/folders where Library Dependency Finder looks for +libraries. These folders/path have priority and LDF operates in the next order: + +1. :ref:`projectconf_lib_extra_dirs` - extra storages per build environment +2. :ref:`projectconf_pio_lib_dir` - own/private library storage per project +3. :ref:`projectconf_pio_piolibdeps_dir` - project dependencies storage used by + :ref:`librarymanager` +4. :ref:`projectconf_pio_home_dir`/lib - global storage per all projects. + +.. _ldf_mode: + +Dependency Finder Mode +---------------------- + +Library Dependency Finder starts work from analyzing source files of the +project (:ref:`projectconf_pio_src_dir`) and can work in the next modes: + +* ``0`` - "manual mode", does not process source files of a project and + dependent libraries. Builds only the libraries that are specified in + manifests (:ref:`library_config`, ``module.json``) or in the :ref:`projectconf`. +* ``1`` - parses ALL C/C++ source code of the project and follows only by + nested includes/chain (``#include ...``) from the libraries. +* ``2`` - **default** - parses ALL C/C++ source code of the project and parses + ALL C/C++ source code of the each dependent library (recursively). + +This mode can be changed using :ref:`projectconf_lib_ldf_mode` option in +:ref:`projectconf`. + +A difference between ``1`` and ``2`` modes. For example, there are 2 libraries: + +* Library "Foo" with files: + + - ``Foo/foo.h`` + - ``Foo/foo.cpp`` + +* Library "Bar" with files: + + - ``Bar/bar.h`` + - ``Bar/bar.cpp`` + +:Case 1: + + * ``lib_ldf_mode = 1`` + * ``Foo/foo.h`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in one of the project source files + + Here are nested includes (``project file > foo.h > bar.h``) and ``LDF`` + will find both libraries "Foo" and "Bar". + +:Case 2: + + * ``lib_ldf_mode = 1`` + * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in one of the project source files + + In this case, ``LDF`` will not find "Bar" library because it doesn't know + about CPP file (``Foo/foo.cpp``). + +:Case 3: + + * ``lib_ldf_mode = 2`` + * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) + * ``#include `` is located in one of the project source files + + Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo" + library and finds ``Foo/foo.cpp`` that depends on ``#include ``. + Secondly, it will parse all sources from "Bar" library and this operation + continues until all dependent libraries will not be parsed. + +.. _ldf_compat_mode: + +Compatibility Mode +------------------ + +Compatibility mode allows to control strictness of Library Dependency Finder. +If library contains one of manifest file (:ref:`library_config`, +``library.properties``, ``module.json``), then LDF check compatibility of this +library with real build environment. Available compatibility modes: + +* ``0`` - does not check for compatibility (is not recommended) +* ``1`` - **default** - checks for the compatibility with + :ref:`projectconf_env_framework` from build environment +* ``2`` - checks for the compatibility with :ref:`projectconf_env_framework` + and :ref:`projectconf_env_platform` from build environment. + +This mode can be changed using :ref:`projectconf_lib_compat_mode` option in +:ref:`projectconf`. + +Manual dependencies +------------------- + +If project or library contains own ``dependencies`` list (see +:ref:`libjson_dependencies`), the LDF will not looking for dependencies in +the source code. The specified libraries will be built automatically without +check. + +.. _ldf_c_cond_syntax: + +C Preprocessor conditional syntax +--------------------------------- + +In spite of the fact that Library Dependency Finder is written in pure Python, +it interprets (emulates) `C Preprocessor conditional syntax `_ +(``#ifdef``, ``if``, ``defined``, ``else``, and ``elif``) without calling +``gcc -E``. For example, + +``platformio.ini`` + +.. code-block:: ini + + [env:myenv] + build_flags = -D MY_PROJECT_VERSION=13 + +``mylib.h`` + +.. code-block:: c + + #ifdef PROJECT_VERSION + // include common file for the project + #include "my_common.h" + #endif + + #if PROJECT_VERSION < 10 + // this include will be ignored because does not satisfy condition above + #include "my_old.h" + #endif diff --git a/docs/platforms/unit_testing.rst b/docs/platforms/unit_testing.rst index 19f51e1c..809eb76c 100644 --- a/docs/platforms/unit_testing.rst +++ b/docs/platforms/unit_testing.rst @@ -14,6 +14,8 @@ Unit Testing ============ +.. versionadded:: 3.0 + `Unit Testing (wiki) `_ is a software testing method by which individual units of source code, sets of one or more MCU program modules together with associated control data, diff --git a/docs/projectconf.rst b/docs/projectconf.rst index 3f4a9005..748d0478 100644 --- a/docs/projectconf.rst +++ b/docs/projectconf.rst @@ -44,8 +44,8 @@ Options ``home_dir`` ^^^^^^^^^^^^ -Is used to store platform toolchains, frameworks, external libraries, -service data and etc. +Is used to store platform toolchains, frameworks, global libraries for +:ref: `ldf`, service data and etc. A default value is User's home directory: @@ -60,18 +60,59 @@ This option can be overridden by global environment variable ``lib_dir`` ^^^^^^^^^^^ -This directory is used to store external libraries downloaded by -:ref:`librarymanager`. +You can put here your own/private libraries. The source code of each library +should be placed in separate directory, like +``lib/private_lib/[here are source files]``. This directory has the highest +priority for :ref:`ldf`. -A default value is ``%home_dir%/lib``. +A default value is ``lib`` that means that folder is located in the root of +project. This option can be overridden by global environment variable :envvar:`PLATFORMIO_LIB_DIR`. -.. note:: - You can put here your own/private libraries. The source code of each - library should be placed in separate directory. For example, - ``%lib_dir%/private_lib/[here are source files]``. +For example, see how can be organized ``Foo`` and ``Bar`` libraries: + +.. code:: + + |--lib + | |--Bar + | | |--docs + | | |--examples + | | |--src + | | |- Bar.c + | | |- Bar.h + | |--Foo + | | |- Foo.c + | | |- Foo.h + |- platformio.ini + |--src + |- main.c + + +Then in ``src/main.c`` you should use: + +.. code-block:: c + + #include + #include + + // rest H/C/CPP code + +PlatformIO will find your libraries automatically, configure preprocessor's +include paths and build them. + +.. _projectconf_pio_piolibdeps_dir: + +``piolibdeps_dir`` +^^^^^^^^^^^^^^^^^^ + +Internal storage where :ref:`librarymanager` will install project dependencies. +A default value is ``.piolibdeps`` that means that folder is located in the root of +project. + +This option can be overridden by global environment variable +:envvar:`PLATFORMIO_PIOLIBDEPS_DIR`. .. _projectconf_pio_src_dir: @@ -79,10 +120,8 @@ This option can be overridden by global environment variable ^^^^^^^^^^^ A path to project's source directory. PlatformIO uses it for :ref:`cmd_run` -command. - -A default value is ``src`` which means that folder is located in the root of -project. +command. A default value is ``src`` that means that folder is located in the +root of project. This option can be overridden by global environment variable :envvar:`PLATFORMIO_SRC_DIR`. @@ -110,7 +149,7 @@ fast! then PlatformIO will remove this folder automatically. It will be created on the next build operation. -A default value is ``.pioenvs`` which means that folder is located in the root of +A default value is ``.pioenvs`` that means that folder is located in the root of project. This option can be overridden by global environment variable @@ -127,8 +166,7 @@ This option can be overridden by global environment variable ^^^^^^^^^^^^ Data directory to store contents and :ref:`platform_espressif_uploadfs`. - -A default value is ``data`` which means that folder is located in the root of +A default value is ``data`` that means that folder is located in the root of project. This option can be overridden by global environment variable @@ -139,9 +177,8 @@ This option can be overridden by global environment variable ``test_dir`` ^^^^^^^^^^^^ -Directory for :ref:`unit_testing`. - -A default value is ``test`` which means that folder is located in the root of +Directory where :ref:`unit_testing` engine will look for the tests. +A default value is ``test`` that means that folder is located in the root of project. This option can be overridden by global environment variable @@ -206,6 +243,9 @@ For example, ``[env:hello_world]``. General options ~~~~~~~~~~~~~~~ +.. contents:: + :local: + .. _projectconf_env_platform: ``platform`` @@ -265,6 +305,9 @@ using `PlatformIO Embedded Boards Explorer `_. Board options ~~~~~~~~~~~~~ +.. contents:: + :local: + ``board_mcu`` ^^^^^^^^^^^^^ @@ -309,8 +352,11 @@ This option isn't available for the all development platforms. The only Flash chip interface mode. This option isn't available for the all development platforms. The only :ref:`platform_espressif` supports it. -Building options -~~~~~~~~~~~~~~~~ +Build options +~~~~~~~~~~~~~ + +.. contents:: + :local: .. _projectconf_build_flags: @@ -456,7 +502,7 @@ be applied in theirs order. By default, ``src_filter`` is predefined to ``+<*> -<.git/> - - - - -``, -which means "includes ALL files, then +that means "includes ALL files, then exclude ``.git`` and ``svn`` repository folders, ``example`` ... folder. This option can be set by global environment variable @@ -529,8 +575,11 @@ The list with available targets is located in :option:`platformio run --target`. When no targets are defined, *PlatformIO* will build only sources by default. -Uploading options -~~~~~~~~~~~~~~~~~ +Upload options +~~~~~~~~~~~~~~ + +.. contents:: + :local: .. _projectconf_upload_port: @@ -587,6 +636,9 @@ development platforms. The only :ref:`platform_espressif` supports it. Library options ~~~~~~~~~~~~~~~ +.. contents:: + :local: + ``lib_install`` ^^^^^^^^^^^^^^^ @@ -603,12 +655,17 @@ Example: [env:depends_on_some_libs] lib_install = 1,13,19 +.. _projectconf_lib_force: + ``lib_force`` ^^^^^^^^^^^^^ -Force Library Build System to build specified libraries if they even are not -included in the project source code. Also, these libraries will be processed -in the first order. +.. seealso:: + Please make sure to read :ref:`ldf` guide first. + +Force Library Dependency Finder to depend on the specified libraries if +they even are not included in the project source code. Also, these +libraries will be processed in the first order. The correct value for this option is library name (not folder name). In the most cases, library name is pre-defined in manifest file @@ -627,7 +684,8 @@ Example: ``lib_ignore`` ^^^^^^^^^^^^^^ -Please make sure to read :ref:`faq_ldf` guides first. +.. seealso:: + Please make sure to read :ref:`ldf` guide first. Specify libraries which should be ignored by Library Dependency Finder. @@ -643,72 +701,14 @@ Example: [env:ignore_some_libs] lib_ignore = SPI, Ethernet -.. _projectconf_lib_deep_search: - -``lib_deep_search`` -^^^^^^^^^^^^^^^^^^^ - -Please make sure to read :ref:`faq_ldf` guides first. - -By default, this option is turned ON (``lib_deep_search = true``) and means -that Library Dependency Finder will analyze ALL source files from the library -and will try automatically find all dependencies. - -If you want to disable deep search, please set this option to ``false``. -Note! Some libraries depend on other libraries and the -``#include <...>`` directives for these libraries are not declared in the -"main" header file that is used by upper library. If LDF is turned OFF -(``lib_deep_search = false``), it will not handle these libraries automatically -because it doesn't analyze "each source file" of the nested libraries -(only "nested includes/chain"). - -For example, there are 2 libraries: - -* Library "Foo" with files: - - - ``Foo/foo.h`` - - ``Foo/foo.cpp`` - -* Library "Bar" with files: - - - ``Bar/bar.h`` - - ``Bar/bar.cpp`` - -:Case 1: - - * ``lib_deep_search = false`` - * ``Foo/foo.h`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in one of the project source files - - Here are nested includes (``project file > foo.h > bar.h``) and ``LDF`` will - find both libraries "Foo" and "Bar". - -:Case 2: - - * ``lib_deep_search = false`` - * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in one of the project source files - - In this case, ``LDF`` will not find "Bar" library because it doesn't know - about CPP file (``Foo/foo.cpp``). - -:Case 3: - - * ``lib_deep_search = true`` - * ``Foo/foo.cpp`` depends on "Bar" library (contains ``#include ``) - * ``#include `` is located in one of the project source files - - Firstly, ``LDF`` finds "Foo" library, then it parses all sources from "Foo" - library and finds ``Foo/foo.cpp`` that depends on ``#include ``. - Secondly, it will parse all sources from "Bar" library and this operation - continues until all dependent libraries will not be parsed. - .. _projectconf_lib_extra_dirs: ``lib_extra_dirs`` ^^^^^^^^^^^^^^^^^^ -Please make sure to read :ref:`faq_ldf` guides first. +.. versionadded:: 3.0 +.. seealso:: + Please make sure to read :ref:`ldf` guide first. A list with extra directories/storages where Library Dependency Finder will look for dependencies. Multiple paths are allowed. Please separate them @@ -729,23 +729,34 @@ Example: [env:custom_lib_dirs] lib_extra_dirs = /path/to/private/dir1,/path/to/private/dir2 +.. _projectconf_lib_ldf_mode: + +``lib_ldf_mode`` +^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.0 +.. seealso:: + Please make sure to read :ref:`ldf` guide first. + +Library Dependency Finder starts work from analyzing source files of the +project (:ref:`projectconf_pio_src_dir`) and can work in the different modes +(see :ref:`ldf_mode`). + +By default, this value is set to ``lib_ldf_mode = 2`` and means that LDF +will parse ALL C/C++ source code of the project and will parse ALL C/C++ +source code of the each dependent library (recursively). + .. _projectconf_lib_compat_mode: ``lib_compat_mode`` ^^^^^^^^^^^^^^^^^^^ -Please make sure to read :ref:`faq_ldf` guides first. +.. versionadded:: 3.0 +.. seealso:: + Please make sure to read :ref:`ldf` guide first. -Library compatibility mode that allows to control Library Dependency Finder -strictness. If library contains manifest file (:ref:`library_config`, -``library.properties``, ``module.json``), then LDF check compatibility of this -library with real build environment. Available compatibility modes: - -* ``0`` - don't check for compatibility -* ``1`` - check for the compatibility with :ref:`projectconf_env_framework` - from build environment -* ``2`` - check for the compatibility with :ref:`projectconf_env_framework` - and :ref:`projectconf_env_platform` from build environment. +Library compatibility mode allows to control strictness of Library Dependency +Finder. More details :ref:`ldf_compat_mode`. By default, this value is set to ``lib_compat_mode = 1`` and means that LDF will check only for framework compatibility. diff --git a/docs/userguide/cmd_test.rst b/docs/userguide/cmd_test.rst index 628be957..0749f6ec 100644 --- a/docs/userguide/cmd_test.rst +++ b/docs/userguide/cmd_test.rst @@ -14,6 +14,8 @@ platformio test =============== +.. versionadded:: 3.0 + .. contents:: Usage diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 40184898..493f1a22 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -44,7 +44,7 @@ commonvars.AddVariables( ("SRC_FILTER",), # library options - ("LIB_DEEP_SEARCH",), + ("LIB_LDF_MODE",), ("LIB_COMPAT_MODE",), ("LIB_IGNORE",), ("LIB_FORCE",), @@ -63,41 +63,35 @@ commonvars.AddVariables( ("UPLOAD_SPEED",), ("UPLOAD_FLAGS",), ("UPLOAD_RESETMETHOD",) -) +) # yapf: disable DefaultEnvironment( tools=[ "ar", "as", "gcc", "g++", "gnulink", "platformio", "devplatform", "piolib", "piotest", "pioupload", "pioar", "piomisc" - ], + ], # yapf: disable toolpath=[join(util.get_source_dir(), "builder", "tools")], variables=commonvars, # Propagating External Environment ENV=environ, - UNIX_TIME=int(time()), PROGNAME="program", - PIOHOME_DIR=util.get_home_dir(), PROJECT_DIR=util.get_project_dir(), - PROJECTLIB_DIR=util.get_projectlib_dir(), PROJECTSRC_DIR=util.get_projectsrc_dir(), PROJECTTEST_DIR=util.get_projecttest_dir(), PROJECTDATA_DIR=util.get_projectdata_dir(), - PIOENVS_DIR=util.get_pioenvs_dir(), - - BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"), + PROJECTPIOENVS_DIR=util.get_projectpioenvs_dir(), + BUILD_DIR=join("$PROJECTPIOENVS_DIR", "$PIOENV"), BUILDSRC_DIR=join("$BUILD_DIR", "src"), BUILDTEST_DIR=join("$BUILD_DIR", "test"), LIBSOURCE_DIRS=[ - "$PROJECTLIB_DIR", - util.get_lib_dir() + util.get_projectlib_dir(), util.get_projectlibdeps_dir(), + join("$PIOHOME_DIR", "lib") ], - - PYTHONEXE=normpath(sys.executable) -) + PYTHONEXE=normpath(sys.executable)) env = DefaultEnvironment() @@ -126,10 +120,9 @@ env.Prepend(LIBSOURCE_DIRS=env.get("LIB_EXTRA_DIRS", [])) env.LoadDevPlatform(commonvars) env.SConscriptChdir(0) -env.SConsignFile(join("$PIOENVS_DIR", ".sconsign.dblite")) +env.SConsignFile(join("$PROJECTPIOENVS_DIR", ".sconsign.dblite")) env.SConscript("$BUILD_SCRIPT") - if "UPLOAD_FLAGS" in env: env.Append(UPLOADERFLAGS=["$UPLOAD_FLAGS"]) diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 7e94f784..bfa941da 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -194,7 +194,7 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes if not search_paths: search_paths = tuple() assert isinstance(search_paths, tuple) - deep_search = self.env.get("LIB_DEEP_SEARCH", "true").lower() == "true" + deep_search = int(self.env.get("LIB_LDF_MODE", 2)) == 2 if not self._scanned_paths and ( isinstance(self, ProjectAsLibBuilder) or deep_search): @@ -270,6 +270,10 @@ class LibBuilderBase(object): # pylint: disable=too-many-instance-attributes "Error: Could not find `%s` dependency for `%s` " "library\n" % (item['name'], self.name)) self.env.Exit(2) + + # when LDF is disabled + if "LIB_LDF_MODE" in self.env and \ + int(self.env.get("LIB_LDF_MODE")) == 0: return lib_inc_map = {} diff --git a/platformio/exception.py b/platformio/exception.py index 9b117740..33a49e77 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -109,7 +109,7 @@ class FDSHASumMismatch(PlatformioException): "is not equal to remote '{2}'" -class NotPlatformProject(PlatformioException): +class NotPlatformIOProject(PlatformioException): MESSAGE = "Not a PlatformIO project. `platformio.ini` file has not been "\ "found in current working directory ({0}). To initialize new project "\ diff --git a/platformio/util.py b/platformio/util.py index 8cc9645b..2eeaec55 100644 --- a/platformio/util.py +++ b/platformio/util.py @@ -156,7 +156,7 @@ def _get_projconf_option_dir(name, default=None): if option_dir.startswith("~"): option_dir = expanduser(option_dir) return abspath(option_dir) - except exception.NotPlatformProject: + except exception.NotPlatformIOProject: pass return default @@ -180,13 +180,6 @@ def get_home_dir(): return home_dir -def get_lib_dir(): - return _get_projconf_option_dir( - "lib_dir", - join(get_home_dir(), "lib") - ) - - def get_source_dir(): curpath = abspath(__file__) if not isfile(curpath): @@ -201,29 +194,33 @@ def get_project_dir(): return os.getcwd() -def get_projectsrc_dir(): - return _get_projconf_option_dir( - "src_dir", - join(get_project_dir(), "src") - ) - - -def get_projecttest_dir(): - return _get_projconf_option_dir( - "test_dir", - join(get_project_dir(), "test") - ) +def is_platformio_project(project_dir=None): + if not project_dir: + project_dir = get_project_dir() + return isfile(join(project_dir, "platformio.ini")) def get_projectlib_dir(): - return join(get_project_dir(), "lib") + return _get_projconf_option_dir("lib_dir", join(get_project_dir(), "lib")) -def get_pioenvs_dir(): - path = _get_projconf_option_dir( - "envs_dir", - join(get_project_dir(), ".pioenvs") - ) +def get_projectlibdeps_dir(): + return _get_projconf_option_dir("libdeps_dir", + join(get_project_dir(), ".piolibdeps")) + + +def get_projectsrc_dir(): + return _get_projconf_option_dir("src_dir", join(get_project_dir(), "src")) + + +def get_projecttest_dir(): + return _get_projconf_option_dir("test_dir", join(get_project_dir(), + "test")) + + +def get_projectpioenvs_dir(): + path = _get_projconf_option_dir("envs_dir", + join(get_project_dir(), ".pioenvs")) if not isdir(path): os.makedirs(path) dontmod_path = join(path, "do-not-modify-files-here.url") @@ -247,18 +244,12 @@ def load_project_config(project_dir=None): if not project_dir: project_dir = get_project_dir() if not is_platformio_project(project_dir): - raise exception.NotPlatformProject(project_dir) + raise exception.NotPlatformIOProject(project_dir) cp = ConfigParser() cp.read(join(project_dir, "platformio.ini")) return cp -def is_platformio_project(project_dir=None): - if not project_dir: - project_dir = get_project_dir() - return isfile(join(project_dir, "platformio.ini")) - - def change_filemtime(path, time): os.utime(path, (time, time)) @@ -358,6 +349,12 @@ def get_request_defheaders(): )} +@memoized +def _api_request_session(): + import requests + return requests.Session() + + def get_api_result(path, params=None, data=None, skipdns=False): import requests result = None @@ -371,12 +368,14 @@ def get_api_result(path, params=None, data=None, skipdns=False): try: if data: - r = requests.post( + r = _api_request_session().post( url + path, params=params, data=data, headers=headers) else: - r = requests.get(url + path, params=params, headers=headers) - r.raise_for_status() + r = _api_request_session().get(url + path, + params=params, + headers=headers) result = r.json() + r.raise_for_status() except requests.exceptions.HTTPError as e: if result and "errors" in result: raise exception.APIRequestError(result['errors'][0]['title'])