diff --git a/HISTORY.rst b/HISTORY.rst index e3404124..7004f29e 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -9,6 +9,7 @@ PlatformIO 4.0 * **Project Configuration** + - New project configuration parser with a strict options typing (`API `__) - Unified workspace storage (`workspace_dir `__ -> ``.pio``) for PlatformIO Build System, Library Manager, and other internal services (`issue #1778 `_) - Switched to workspace ``.pio/build`` folder for build artifacts instead of ``.pioenvs`` - Share common (global) options between project environments using `[env] `__ section (`issue #1643 `_) diff --git a/docs b/docs index e9107b7d..683b3459 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit e9107b7dc8280bbb25b79ca61f71815986869aa6 +Subproject commit 683b3459e2b558a36dd0e0d3c46a38926f85fa94 diff --git a/platformio/commands/debug/helpers.py b/platformio/commands/debug/helpers.py index 88b4f64a..9b74f190 100644 --- a/platformio/commands/debug/helpers.py +++ b/platformio/commands/debug/helpers.py @@ -88,12 +88,6 @@ def validate_debug_options(cmd_ctx, env_options): "executable": None, "arguments": env_options.get("debug_server") } - if not isinstance(server_options['arguments'], list): - server_options['arguments'] = server_options['arguments'].split( - "\n") - server_options['arguments'] = [ - arg.strip() for arg in server_options['arguments'] if arg.strip() - ] server_options['executable'] = server_options['arguments'][0] server_options['arguments'] = server_options['arguments'][1:] elif "server" in tool_settings: diff --git a/platformio/exception.py b/platformio/exception.py index 343dc03f..09d7d2f9 100644 --- a/platformio/exception.py +++ b/platformio/exception.py @@ -179,6 +179,11 @@ class UnknownEnvNames(PlatformIOProjectException): MESSAGE = "Unknown environment names '{0}'. Valid names are '{1}'" +class ProjectOptionValueError(PlatformIOProjectException): + + MESSAGE = "{0} for option `{1}` in section [{2}]" + + # # Library # diff --git a/platformio/project/config.py b/platformio/project/config.py index 48a06bf6..0f6326a7 100644 --- a/platformio/project/config.py +++ b/platformio/project/config.py @@ -43,6 +43,7 @@ CONFIG_HEADER = """;PlatformIO Project Configuration File class ProjectConfig(object): + INLINE_COMMENT_RE = re.compile(r"\s+;.*$") VARTPL_RE = re.compile(r"\$\{([^\.\}]+)\.([^\}]+)\}") expand_interpolations = True @@ -55,14 +56,15 @@ class ProjectConfig(object): result = [] if not items: return result - inline_comment_re = re.compile(r"\s+;.*$") - for item in items.split("\n" if "\n" in items else ", "): + if not isinstance(items, (list, tuple)): + items = items.split("\n" if "\n" in items else ", ") + for item in items: item = item.strip() # comment if not item or item.startswith((";", "#")): continue if ";" in item: - item = inline_comment_re.sub("", item).strip() + item = ProjectConfig.INLINE_COMMENT_RE.sub("", item).strip() result.append(item) return result @@ -207,20 +209,21 @@ class ProjectConfig(object): if value is None: return default - return self._covert_value(value, option_meta.type) + try: + return self._covert_value(value, option_meta.type) + except click.BadParameter as e: + raise exception.ProjectOptionValueError(e.format_message(), option, + section) @staticmethod def _covert_value(value, to_type): items = value if not isinstance(value, (list, tuple)): items = [value] - for i, v in enumerate(items): - if to_type == bool: - items[i] = v in ("1", "true", "yes", "y") - elif to_type == int: - items[i] = int(v) - elif to_type == float: - items[i] = float(v) + items = [ + to_type(item) if isinstance(to_type, click.ParamType) else item + for item in items + ] return items if isinstance(value, (list, tuple)) else items[0] def envs(self): diff --git a/platformio/project/options.py b/platformio/project/options.py index fd7afd01..e3e3c4ca 100644 --- a/platformio/project/options.py +++ b/platformio/project/options.py @@ -16,6 +16,8 @@ from collections import OrderedDict, namedtuple +import click + ConfigOptionClass = namedtuple("ConfigOption", [ "scope", "name", "type", "multiple", "sysenvvar", "buildenvvar", "oldnames" ]) @@ -128,7 +130,8 @@ ProjectOptions = OrderedDict([ sysenvvar="PLATFORMIO_UPLOAD_PORT", buildenvvar="UPLOAD_PORT"), ConfigEnvOption(name="upload_protocol", buildenvvar="UPLOAD_PROTOCOL"), - ConfigEnvOption(name="upload_speed", buildenvvar="UPLOAD_SPEED"), + ConfigEnvOption( + name="upload_speed", type=click.INT, buildenvvar="UPLOAD_SPEED"), ConfigEnvOption(name="upload_flags", multiple=True, sysenvvar="PLATFORMIO_UPLOAD_FLAGS", @@ -139,8 +142,8 @@ ProjectOptions = OrderedDict([ # Monitor ConfigEnvOption(name="monitor_port"), ConfigEnvOption(name="monitor_speed", oldnames=["monitor_baud"]), - ConfigEnvOption(name="monitor_rts"), - ConfigEnvOption(name="monitor_dtr"), + ConfigEnvOption(name="monitor_rts", type=click.IntRange(0, 1)), + ConfigEnvOption(name="monitor_dtr", type=click.IntRange(0, 1)), ConfigEnvOption(name="monitor_flags", multiple=True), # Library @@ -150,18 +153,23 @@ ProjectOptions = OrderedDict([ ConfigEnvOption(name="lib_ignore", multiple=True), ConfigEnvOption(name="lib_extra_dirs", multiple=True, - sysenvvar="PLATFORMIO_LIB_EXTRA_DIRS"), - ConfigEnvOption(name="lib_ldf_mode"), - ConfigEnvOption(name="lib_compat_mode"), - ConfigEnvOption(name="lib_archive", type=bool), + sysenvvar="PLATFORMIO_LIB_EXTRA_DIRS", + type=click.Path( + exists=True, file_okay=False, dir_okay=True)), + ConfigEnvOption(name="lib_ldf_mode", + type=click.Choice( + ["off", "chain", "deep", "chain+", "deep+"])), + ConfigEnvOption(name="lib_compat_mode", + type=click.Choice(["off", "soft", "strict"])), + ConfigEnvOption(name="lib_archive", type=click.BOOL), # Test ConfigEnvOption(name="test_filter", multiple=True), ConfigEnvOption(name="test_ignore", multiple=True), ConfigEnvOption(name="test_port"), - ConfigEnvOption(name="test_speed"), + ConfigEnvOption(name="test_speed", type=click.INT), ConfigEnvOption(name="test_transport"), - ConfigEnvOption(name="test_build_project_src"), + ConfigEnvOption(name="test_build_project_src", type=click.BOOL), # Debug ConfigEnvOption(name="debug_tool"), @@ -169,10 +177,13 @@ ProjectOptions = OrderedDict([ ConfigEnvOption(name="debug_init_cmds", multiple=True), ConfigEnvOption(name="debug_extra_cmds", multiple=True), ConfigEnvOption(name="debug_load_cmd"), - ConfigEnvOption(name="debug_load_mode"), - ConfigEnvOption(name="debug_server"), + ConfigEnvOption(name="debug_load_mode", + type=click.Choice(["always", "modified", "manual"])), + ConfigEnvOption(name="debug_server", multiple=True), ConfigEnvOption(name="debug_port"), - ConfigEnvOption(name="debug_svd_path"), + ConfigEnvOption(name="debug_svd_path", + type=click.Path( + exists=True, file_okay=True, dir_okay=False)), # Other ConfigEnvOption(name="extra_scripts",