diff --git a/platformio/builder/main.py b/platformio/builder/main.py index 05470451..e3932be5 100644 --- a/platformio/builder/main.py +++ b/platformio/builder/main.py @@ -168,7 +168,7 @@ env.SConsignFile( env.SConscript(env.GetExtraScripts("pre"), exports="env") if env.IsCleanTarget(): - env.CleanProject("cleanall" in COMMAND_LINE_TARGETS) + env.CleanProject(fullclean=int(ARGUMENTS.get("FULLCLEAN", 0))) env.Exit(0) env.SConscript("$BUILD_SCRIPT") diff --git a/platformio/builder/tools/piotarget.py b/platformio/builder/tools/piotarget.py index f2dc774d..32bb5ffe 100644 --- a/platformio/builder/tools/piotarget.py +++ b/platformio/builder/tools/piotarget.py @@ -16,7 +16,6 @@ import os from SCons.Action import Action # pylint: disable=import-error from SCons.Script import ARGUMENTS # pylint: disable=import-error -from SCons.Script import COMMAND_LINE_TARGETS # pylint: disable=import-error from SCons.Script import AlwaysBuild # pylint: disable=import-error from platformio import compat, fs @@ -29,10 +28,10 @@ def VerboseAction(_, act, actstr): def IsCleanTarget(env): - return env.GetOption("clean") or ("cleanall" in COMMAND_LINE_TARGETS) + return env.GetOption("clean") -def CleanProject(env, clean_all=False): +def CleanProject(env, fullclean=False): def _relpath(path): if compat.IS_WINDOWS: prefix = os.getcwd()[:2].lower() @@ -56,7 +55,7 @@ def CleanProject(env, clean_all=False): else: print("Build environment is clean") - if clean_all and os.path.isdir(libdeps_dir): + if fullclean and os.path.isdir(libdeps_dir): _clean_dir(libdeps_dir) print("Done cleaning") diff --git a/platformio/platform/_run.py b/platformio/platform/_run.py index 0c157f85..4fc41f9c 100644 --- a/platformio/platform/_run.py +++ b/platformio/platform/_run.py @@ -25,6 +25,7 @@ from platformio import app, fs, proc, telemetry from platformio.compat import hashlib_encode_data from platformio.package.manager.core import get_core_package_dir from platformio.platform.exception import BuildScriptNotFound +from platformio.run.helpers import KNOWN_CLEAN_TARGETS, KNOWN_FULLCLEAN_TARGETS class PlatformRunMixin: @@ -56,9 +57,6 @@ class PlatformRunMixin: self.silent = silent self.verbose = verbose or app.get_setting("force_verbose") - if "clean" in targets: - targets = ["-c", "."] - variables["platform_manifest"] = self.manifest_path if "build_script" not in variables: @@ -92,10 +90,18 @@ class PlatformRunMixin: "--sconstruct", os.path.join(fs.get_source_dir(), "builder", "main.py"), ] - args.append("PIOVERBOSE=%d" % (1 if self.verbose else 0)) + args.append("PIOVERBOSE=%d" % int(self.verbose)) # pylint: disable=protected-access - args.append("ISATTY=%d" % (1 if click._compat.isatty(sys.stdout) else 0)) - args += targets + args.append("ISATTY=%d" % int(click._compat.isatty(sys.stdout))) + + if set(KNOWN_CLEAN_TARGETS + KNOWN_FULLCLEAN_TARGETS) & set(targets): + args.append("--clean") + args.append( + "FULLCLEAN=%d" + % (1 if set(KNOWN_FULLCLEAN_TARGETS) & set(targets) else 0) + ) + elif targets: + args.extend(targets) # encode and append variables for key, value in variables.items(): diff --git a/platformio/run/cli.py b/platformio/run/cli.py index 92a8057e..dc3eb2ee 100644 --- a/platformio/run/cli.py +++ b/platformio/run/cli.py @@ -26,7 +26,7 @@ from platformio.device.monitor.command import device_monitor_cmd from platformio.project.config import ProjectConfig from platformio.project.exception import ProjectError from platformio.project.helpers import find_project_dir_above, load_build_metadata -from platformio.run.helpers import clean_build_dir, handle_legacy_libdeps +from platformio.run.helpers import clean_build_dir from platformio.run.processor import EnvironmentProcessor from platformio.test.runners.base import CTX_META_TEST_IS_RUNNING @@ -97,10 +97,12 @@ def cli( if os.path.isfile(project_dir): project_dir = find_project_dir_above(project_dir) + targets = list(target) if target else [] + del target + only_monitor = targets == ["monitor"] is_test_running = CTX_META_TEST_IS_RUNNING in ctx.meta - - only_monitor = "monitor" in target and len(target) == 1 command_failed = False + with fs.cd(project_dir): config = ProjectConfig.get_instance(project_conf) config.validate(environment) @@ -108,59 +110,60 @@ def cli( if list_targets: return print_target_list(list(environment) or config.envs()) - if not only_monitor: - # clean obsolete build dir - if not disable_auto_clean: - build_dir = config.get("platformio", "build_dir") - try: - clean_build_dir(build_dir, config) - except ProjectError as exc: - raise exc - except: # pylint: disable=bare-except - click.secho( - "Can not remove temporary directory `%s`. Please remove " - "it manually to avoid build issues" % build_dir, - fg="yellow", - ) - - default_envs = config.default_envs() - results = [] - for env in config.envs(): - skipenv = any( - [ - environment and env not in environment, - not environment and default_envs and env not in default_envs, - ] + # clean obsolete build dir + if not only_monitor and not disable_auto_clean: + build_dir = config.get("platformio", "build_dir") + try: + clean_build_dir(build_dir, config) + except ProjectError as exc: + raise exc + except: # pylint: disable=bare-except + click.secho( + "Can not remove temporary directory `%s`. Please remove " + "it manually to avoid build issues" % build_dir, + fg="yellow", ) - if skipenv: - results.append({"env": env}) - continue - # print empty line between multi environment project - if not silent and any(r.get("succeeded") is not None for r in results): - click.echo() + default_envs = config.default_envs() + results = [] + for env in config.envs(): + skipenv = any( + [ + environment and env not in environment, + not environment and default_envs and env not in default_envs, + ] + ) + if skipenv: + results.append({"env": env}) + continue - results.append( - process_env( - ctx, - env, - config, - target, - upload_port, - jobs, - program_args, - is_test_running, - silent, - verbose, - ) + # print empty line between multi environment project + if not silent and any(r.get("succeeded") is not None for r in results): + click.echo() + + results.append( + process_env( + ctx, + env, + config, + targets, + upload_port, + monitor_port, + jobs, + program_args, + is_test_running, + silent, + verbose, ) - command_failed = any(r.get("succeeded") is False for r in results) - if ( - not is_test_running - and (command_failed or not silent) - and len(results) > 1 - ): - print_processing_summary(results, verbose) + ) + command_failed = any(r.get("succeeded") is False for r in results) + if ( + not is_test_running + and not only_monitor + and (command_failed or not silent) + and len(results) > 1 + ): + print_processing_summary(results, verbose) # Reset custom project config app.set_session_var("custom_project_conf", None) @@ -168,14 +171,6 @@ def cli( if command_failed: raise exception.ReturnErrorCode(1) - if "monitor" in target and "nobuild" not in target: - ctx.invoke( - device_monitor_cmd, - project_dir=project_dir, - port=monitor_port, - environment=environment[0] if environment else None, - ) - return True @@ -185,6 +180,7 @@ def process_env( config, targets, upload_port, + monitor_port, jobs, program_args, is_test_running, @@ -194,22 +190,38 @@ def process_env( if not is_test_running and not silent: print_processing_header(name, config, verbose) - ep = EnvironmentProcessor( - ctx, - name, - config, - targets, - upload_port, - jobs, - program_args, - silent, - verbose, - ) - result = {"env": name, "duration": time(), "succeeded": ep.process()} + targets = targets or config.get(f"env:{name}", "targets", []) + only_monitor = targets == ["monitor"] + result = {"env": name, "duration": time(), "succeeded": True} + + if not only_monitor: + result["succeeded"] = EnvironmentProcessor( + ctx, + name, + config, + [t for t in targets if t != "monitor"], + upload_port, + jobs, + program_args, + silent, + verbose, + ).process() + + if "monitor" in targets and "nobuild" not in targets: + ctx.invoke( + device_monitor_cmd, + port=monitor_port, + environment=name, + ) + result["duration"] = time() - result["duration"] # print footer on error or when is not unit testing - if not is_test_running and (not silent or not result["succeeded"]): + if ( + not is_test_running + and not only_monitor + and (not silent or not result["succeeded"]) + ): print_processing_footer(result) return result diff --git a/platformio/run/helpers.py b/platformio/run/helpers.py index cfa5165c..f8bfdcba 100644 --- a/platformio/run/helpers.py +++ b/platformio/run/helpers.py @@ -18,6 +18,10 @@ from os.path import isdir, isfile, join from platformio import fs from platformio.project.helpers import compute_project_checksum, get_project_dir +KNOWN_CLEAN_TARGETS = ("clean",) +KNOWN_FULLCLEAN_TARGETS = ("cleanall", "fullclean") +KNOWN_ALLCLEAN_TARGETS = KNOWN_CLEAN_TARGETS + KNOWN_FULLCLEAN_TARGETS + def clean_build_dir(build_dir, config): # remove legacy ".pioenvs" folder diff --git a/platformio/run/processor.py b/platformio/run/processor.py index 053478ac..3d427a1b 100644 --- a/platformio/run/processor.py +++ b/platformio/run/processor.py @@ -15,6 +15,7 @@ from platformio.package.commands.install import install_project_env_dependencies from platformio.platform.factory import PlatformFactory from platformio.project.exception import UndefinedEnvPlatformError +from platformio.run.helpers import KNOWN_ALLCLEAN_TARGETS from platformio.test.runners.base import CTX_META_TEST_RUNNING_NAME # pylint: disable=too-many-instance-attributes @@ -36,7 +37,7 @@ class EnvironmentProcessor: self.cmd_ctx = cmd_ctx self.name = name self.config = config - self.targets = [str(t) for t in targets] + self.targets = targets self.upload_port = upload_port self.jobs = jobs self.program_args = program_args @@ -61,33 +62,29 @@ class EnvironmentProcessor: variables["upload_port"] = self.upload_port return variables - def get_build_targets(self): - return ( - self.targets - if self.targets - else self.config.get("env:" + self.name, "targets", []) - ) - def process(self): if "platform" not in self.options: raise UndefinedEnvPlatformError(self.name) build_vars = self.get_build_variables() - build_targets = list(self.get_build_targets()) + is_clean = set(KNOWN_ALLCLEAN_TARGETS) & set(self.targets) + build_targets = list(set(self.targets) - set(KNOWN_ALLCLEAN_TARGETS)) - # skip monitor target, we call it above - if "monitor" in build_targets: - build_targets.remove("monitor") - - if not set(["clean", "cleanall"]) & set(build_targets): - install_project_env_dependencies( - self.name, - { - "project_targets": build_targets, - "piotest_running_name": build_vars.get("piotest_running_name"), - }, - ) + # pre-clean + if is_clean: + result = PlatformFactory.new( + self.options["platform"], autoinstall=True + ).run(build_vars, self.targets, self.silent, self.verbose, self.jobs) + if not build_targets: + return result["returncode"] == 0 + install_project_env_dependencies( + self.name, + { + "project_targets": self.targets, + "piotest_running_name": build_vars.get("piotest_running_name"), + }, + ) result = PlatformFactory.new(self.options["platform"], autoinstall=True).run( build_vars, build_targets, self.silent, self.verbose, self.jobs )