diff --git a/HISTORY.rst b/HISTORY.rst index 371742e900..bfccddfcfd 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -10,6 +10,8 @@ PlatformIO 3.0 * Improved detecting of ARM mbed media disk for uploading * Improved Project Generator for CLion IDE when source folder contains nested items * Changed default exit combination for Device Monitor from ``Ctrl+]`` to ``Ctrl+C`` +* Improved handling of library dependencies specified in ``library.json`` manifest + (`issue #814 `_) * Fixed issue with ``PATH`` auto-configuring for upload tools * Fixed ``99-platformio-udev.rules`` checker for Linux OS diff --git a/platformio/__init__.py b/platformio/__init__.py index 6c7aaeb4d2..eebe61411a 100644 --- a/platformio/__init__.py +++ b/platformio/__init__.py @@ -14,7 +14,7 @@ import sys -VERSION = (3, 2, "0a8") +VERSION = (3, 2, "0a9") __version__ = ".".join([str(s) for s in VERSION]) __title__ = "platformio" diff --git a/platformio/builder/main.py b/platformio/builder/main.py index ef05256745..359199cc5e 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -121,7 +121,7 @@ env[var] = environ.get(k) # Parse comma separated items -for opt in ("LIB_DEPS", "LIB_IGNORE", "LIB_EXTRA_DIRS"): +for opt in ("PIOFRAMEWORK", "LIB_DEPS", "LIB_IGNORE", "LIB_EXTRA_DIRS"): if opt not in env: continue env[opt] = [l.strip() for l in env[opt].split(", ") if l.strip()] diff --git a/platformio/builder/tools/piolib.py b/platformio/builder/tools/piolib.py index 7283509fc3..20c8b8933f 100644 --- a/platformio/builder/tools/piolib.py +++ b/platformio/builder/tools/piolib.py @@ -37,12 +37,9 @@ def new(env, path): if isfile(join(path, "library.json")): clsname = "PlatformIOLibBuilder" else: - env_frameworks = [ - f.lower().strip() - for f in env.get("PIOFRAMEWORK", "").split(",") - ] used_frameworks = LibBuilderFactory.get_used_frameworks(env, path) - common_frameworks = set(env_frameworks) & set(used_frameworks) + common_frameworks = (set(env.get("PIOFRAMEWORK", [])) & + set(used_frameworks)) if common_frameworks: clsname = "%sLibBuilder" % list(common_frameworks)[0].title() elif used_frameworks: @@ -166,10 +163,24 @@ def depbuilders(self): def dependent(self): return self._is_dependent - def is_platform_compatible(self, platform): + @staticmethod + def items_in_list(items, ilist): + + def _items_to_list(items_): + if not isinstance(items_, list): + items_ = [i.strip() for i in items_.split(",")] + return [i.lower() for i in items_ if i] + + items = _items_to_list(items) + ilist = _items_to_list(ilist) + if "*" in items or "*" in ilist: + return True + return set(items) & set(ilist) + + def is_platforms_compatible(self, platforms): return True - def is_framework_compatible(self, framework): + def is_frameworks_compatible(self, frameworks): return True def load_manifest(self): @@ -189,24 +200,37 @@ def process_extra_options(self): if self.extra_script: self.env.SConscript( realpath(self.extra_script), - exports={"env": self.env, - "pio_lib_builder": self}) + exports={ + "env": self.env, + "pio_lib_builder": self + }) def _process_dependencies(self, lib_builders): if not self.dependencies: return + verbose = (int(ARGUMENTS.get("PIOVERBOSE", 0)) and + not self.env.GetOption('clean')) for item in self.dependencies: + skip = False + for key in ("platforms", "frameworks"): + if (key in item and not self.items_in_list( + self.env["PIO" + key.upper()[:-1]], item[key])): + if verbose: + sys.stderr.write("Skip %s incompatible dependency %s\n" + % (key[:-1], item)) + skip = True + if skip: + continue + found = False for lb in lib_builders: if item['name'] != lb.name: continue elif "frameworks" in item and \ - not any([lb.is_framework_compatible(f) - for f in item["frameworks"]]): + not lb.is_frameworks_compatible(item["frameworks"]): continue elif "platforms" in item and \ - not any([lb.is_platform_compatible(p) - for p in item["platforms"]]): + not lb.is_platforms_compatible(item["platforms"]): continue found = True self.depend_recursive(lb, lib_builders) @@ -383,8 +407,8 @@ def src_filter(self): src_filter.append("+" % (sep, ext)) return src_filter - def is_framework_compatible(self, framework): - return framework.lower() in ("arduino", "energia") + def is_frameworks_compatible(self, frameworks): + return self.items_in_list(frameworks, ["arduino", "energia"]) class MbedLibBuilder(LibBuilderBase): @@ -408,8 +432,8 @@ def get_inc_dirs(self): inc_dirs.append(join(self.path, p)) return inc_dirs - def is_framework_compatible(self, framework): - return framework.lower() == "mbed" + def is_frameworks_compatible(self, frameworks): + return self.items_in_list(frameworks, ["mbed"]) class PlatformIOLibBuilder(LibBuilderBase): @@ -461,24 +485,17 @@ def lib_ldf_mode(self): return int(self._manifest.get("build").get("libLDFMode")) return LibBuilderBase.lib_ldf_mode.fget(self) - def is_platform_compatible(self, platform): + def is_platforms_compatible(self, platforms): items = self._manifest.get("platforms") if not items: - return LibBuilderBase.is_platform_compatible(self, platform) - return self._item_in_list(platform, items) + return LibBuilderBase.is_platforms_compatible(self, platforms) + return self.items_in_list(platforms, items) - def is_framework_compatible(self, framework): + def is_frameworks_compatible(self, frameworks): items = self._manifest.get("frameworks") if not items: - return LibBuilderBase.is_framework_compatible(self, framework) - return self._item_in_list(framework, items) - - def _item_in_list(self, item, ilist): - if ilist == "*": - return True - if not isinstance(ilist, list): - ilist = [i.strip() for i in ilist.split(",")] - return item.lower() in [i.lower() for i in ilist] + return LibBuilderBase.is_frameworks_compatible(self, frameworks) + return self.items_in_list(frameworks, items) def get_inc_dirs(self): inc_dirs = LibBuilderBase.get_inc_dirs(self) @@ -497,9 +514,6 @@ def get_inc_dirs(self): def GetLibBuilders(env): items = [] - env_frameworks = [ - f.lower().strip() for f in env.get("PIOFRAMEWORK", "").split(",") - ] compat_mode = int(env.get("LIB_COMPAT_MODE", 1)) verbose = (int(ARGUMENTS.get("PIOVERBOSE", 0)) and not env.GetOption('clean')) @@ -509,14 +523,14 @@ def _check_lib_builder(lb): if verbose: sys.stderr.write("Ignored library %s\n" % lb.path) return - if compat_mode > 1 and not lb.is_platform_compatible(env[ + if compat_mode > 1 and not lb.is_platforms_compatible(env[ 'PIOPLATFORM']): if verbose: sys.stderr.write("Platform incompatible library %s\n" % lb.path) return False - if compat_mode > 0 and not any([lb.is_framework_compatible(f) - for f in env_frameworks]): + if compat_mode > 0 and "PIOFRAMEWORK" in env and \ + not lb.is_frameworks_compatible(env.get("PIOFRAMEWORK", [])): if verbose: sys.stderr.write("Framework incompatible library %s\n" % lb.path) diff --git a/platformio/builder/tools/pioupload.py b/platformio/builder/tools/pioupload.py index 9a8ec8c63b..e78df88ea2 100644 --- a/platformio/builder/tools/pioupload.py +++ b/platformio/builder/tools/pioupload.py @@ -114,7 +114,7 @@ def _look_for_serial_port(): print env.subst("Use manually specified: $UPLOAD_PORT") return - if env.subst("$PIOFRAMEWORK") == "mbed": + if "mbed" in env.subst("$PIOFRAMEWORK"): env.Replace(UPLOAD_PORT=_look_for_mbed_disk()) else: if (system() == "Linux" and not any([ diff --git a/platformio/builder/tools/platformio.py b/platformio/builder/tools/platformio.py index 06eee2a96b..f49b3b2d18 100644 --- a/platformio/builder/tools/platformio.py +++ b/platformio/builder/tools/platformio.py @@ -52,10 +52,7 @@ def _append_pio_macros(): # apply user flags env.ProcessFlags(env.get("BUILD_FLAGS")) - if env.get("PIOFRAMEWORK"): - env.BuildFrameworks([ - f.lower().strip() for f in env['PIOFRAMEWORK'].split(",") - ]) + env.BuildFrameworks(env.get("PIOFRAMEWORK")) # restore PIO macros if it was deleted by framework _append_pio_macros() diff --git a/platformio/managers/lib.py b/platformio/managers/lib.py index e3edaca033..fec5020fbd 100644 --- a/platformio/managers/lib.py +++ b/platformio/managers/lib.py @@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pylint: disable=too-many-arguments, too-many-locals, too-many-branches + import json import os from hashlib import md5 @@ -185,7 +187,9 @@ def _get_pkg_id_by_name(self, if "id" in manifest: return int(manifest['id']) return int( - self.search_for_library({"name": name}, silent, interactive)['id']) + self.search_for_library({ + "name": name + }, silent, interactive)['id']) def _install_from_piorepo(self, name, requirements): assert name.startswith("id=") @@ -203,7 +207,7 @@ def _install_from_piorepo(self, name, requirements): name, dl_data['url'].replace("http://", "https://") if app.get_setting("enable_ssl") else dl_data['url'], requirements) - def install(self, # pylint: disable=too-many-arguments, too-many-locals + def install(self, name, requirements=None, silent=False, @@ -247,7 +251,8 @@ def install(self, # pylint: disable=too-many-arguments, too-many-locals lib_info = self.search_for_library(filters, silent, interactive) except exception.LibNotFound as e: - click.secho("Warning! %s" % e, fg="yellow") + if not silent: + click.secho("Warning! %s" % e, fg="yellow") continue if filters.get("version"): diff --git a/platformio/managers/platform.py b/platformio/managers/platform.py index 546cd65b51..dbab2c587a 100644 --- a/platformio/managers/platform.py +++ b/platformio/managers/platform.py @@ -441,7 +441,10 @@ def pkg_types_to_names(self, types): def configure_default_packages(self, variables, targets): # enable used frameworks - for framework in variables.get("pioframework", "").split(","): + frameworks = variables.get("pioframework", []) + if not isinstance(frameworks, list): + frameworks = frameworks.split(", ") + for framework in frameworks: if not self.frameworks: continue framework = framework.lower().strip()