Пример #1
0
def cli(ctx, **options):
    storage_cmds = ("install", "uninstall", "update", "list")
    # skip commands that don't need storage folder
    if ctx.invoked_subcommand not in storage_cmds or (
        len(ctx.args) == 2 and ctx.args[1] in ("-h", "--help")
    ):
        return
    storage_dirs = list(options["storage_dir"])
    if options["global"]:
        storage_dirs.append(get_project_global_lib_dir())
    if not storage_dirs:
        if is_platformio_project():
            storage_dirs = [get_project_dir()]
        elif is_ci():
            storage_dirs = [get_project_global_lib_dir()]
            click.secho(
                "Warning! Global library storage is used automatically. "
                "Please use `platformio lib --global %s` command to remove "
                "this warning." % ctx.invoked_subcommand,
                fg="yellow",
            )

    if not storage_dirs:
        raise NotGlobalLibDir(
            get_project_dir(), get_project_global_lib_dir(), ctx.invoked_subcommand
        )

    in_silence = PlatformioCLI.in_silence()
    ctx.meta[CTX_META_PROJECT_ENVIRONMENTS_KEY] = options["environment"]
    ctx.meta[CTX_META_INPUT_DIRS_KEY] = storage_dirs
    ctx.meta[CTX_META_STORAGE_DIRS_KEY] = []
    ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY] = {}
    for storage_dir in storage_dirs:
        if not is_platformio_project(storage_dir):
            ctx.meta[CTX_META_STORAGE_DIRS_KEY].append(storage_dir)
            continue
        with fs.cd(storage_dir):
            config = ProjectConfig.get_instance(
                os.path.join(storage_dir, "platformio.ini")
            )
            config.validate(options["environment"], silent=in_silence)
            libdeps_dir = config.get_optional_dir("libdeps")
            for env in config.envs():
                if options["environment"] and env not in options["environment"]:
                    continue
                storage_dir = os.path.join(libdeps_dir, env)
                ctx.meta[CTX_META_STORAGE_DIRS_KEY].append(storage_dir)
                ctx.meta[CTX_META_STORAGE_LIBDEPS_KEY][storage_dir] = config.get(
                    "env:" + env, "lib_deps", []
                )
Пример #2
0
    def load_state():
        with app.State(AppRPC.APPSTATE_PATH, lock=True) as state:
            storage = state.get("storage", {})

            # base data
            caller_id = app.get_session_var("caller_id")
            storage['cid'] = app.get_cid()
            storage['coreVersion'] = __version__
            storage['coreSystype'] = util.get_systype()
            storage['coreCaller'] = (str(caller_id).lower()
                                     if caller_id else None)
            storage['coreSettings'] = {
                name: {
                    "description": data['description'],
                    "default_value": data['value'],
                    "value": app.get_setting(name)
                }
                for name, data in app.DEFAULT_SETTINGS.items()
            }

            storage['homeDir'] = expanduser("~")
            storage['projectsDir'] = storage['coreSettings']['projects_dir'][
                'value']

            # skip non-existing recent projects
            storage['recentProjects'] = [
                p for p in storage.get("recentProjects", [])
                if is_platformio_project(p)
            ]

            state['storage'] = storage
            return state.as_dict()
Пример #3
0
def project_data(project_dir, environment, json_output):
    if not is_platformio_project(project_dir):
        raise NotPlatformIOProjectError(project_dir)
    with fs.cd(project_dir):
        config = ProjectConfig.get_instance()
        config.validate(environment)
        environment = list(environment or config.envs())

    if json_output:
        return click.echo(
            json.dumps(load_project_ide_data(project_dir, environment)))

    for envname in environment:
        click.echo("Environment: " +
                   click.style(envname, fg="cyan", bold=True))
        click.echo("=" * (13 + len(envname)))
        click.echo(
            tabulate(
                [(click.style(name, bold=True), "=", json.dumps(value,
                                                                indent=2))
                 for name, value in load_project_ide_data(
                     project_dir, envname).items()],
                tablefmt="plain",
            ))
        click.echo()

    return None
Пример #4
0
def _save_deps(ctx, pkgs, action="add"):
    specs = []
    for library, pkg in pkgs.items():
        spec = PackageSpec(library)
        if spec.external:
            specs.append(spec)
        else:
            specs.append(
                PackageSpec(
                    owner=pkg.metadata.spec.owner,
                    name=pkg.metadata.spec.name,
                    requirements=spec.requirements
                    or (
                        ("^%s" % pkg.metadata.version)
                        if not pkg.metadata.version.build
                        else pkg.metadata.version
                    ),
                )
            )

    input_dirs = ctx.meta.get(CTX_META_INPUT_DIRS_KEY, [])
    project_environments = ctx.meta[CTX_META_PROJECT_ENVIRONMENTS_KEY]
    for input_dir in input_dirs:
        if not is_platformio_project(input_dir):
            continue
        save_project_libdeps(input_dir, specs, project_environments, action=action)
Пример #5
0
    def load_state():
        with app.State(AppRPC.APPSTATE_PATH, lock=True) as state:
            storage = state.get("storage", {})

            # base data
            caller_id = app.get_session_var("caller_id")
            storage["cid"] = app.get_cid()
            storage["coreVersion"] = __version__
            storage["coreSystype"] = util.get_systype()
            storage["coreCaller"] = str(
                caller_id).lower() if caller_id else None
            storage["coreSettings"] = {
                name: {
                    "description": data["description"],
                    "default_value": data["value"],
                    "value": app.get_setting(name),
                }
                for name, data in app.DEFAULT_SETTINGS.items()
            }

            storage["homeDir"] = fs.expanduser("~")
            storage["projectsDir"] = storage["coreSettings"]["projects_dir"][
                "value"]

            # skip non-existing recent projects
            storage["recentProjects"] = [
                p for p in storage.get("recentProjects", [])
                if is_platformio_project(p)
            ]

            state["storage"] = storage
            state.modified = False  # skip saving extra fields
            return state.as_dict()
Пример #6
0
    def __init__(self, clone: Clone, env):
        self.kind = Kind.BUILTIN
        self.build = BuildModel(kind=self.kind,
                                env=env,
                                version=clone.version,
                                sha1=str(clone.sha1))
        self.clone = clone
        self.path = self.clone.path
        self.package_manager = None
        self._old_dir = None
        self.project_config = None

        if not is_platformio_project(self.path):
            logger.error(f"Raising FileNotFoundError for path: {self.path}")
            raise FileNotFoundError(self.path)
Пример #7
0
    async def import_arduino(self, board, use_arduino_libs,
                             arduino_project_dir):
        board = str(board)
        # don't import PIO Project
        if is_platformio_project(arduino_project_dir):
            return arduino_project_dir

        is_arduino_project = any([
            os.path.isfile(
                os.path.join(
                    arduino_project_dir,
                    "%s.%s" % (os.path.basename(arduino_project_dir), ext),
                )) for ext in ("ino", "pde")
        ])
        if not is_arduino_project:
            raise jsonrpc.exceptions.JSONRPCDispatchException(
                code=4000,
                message="Not an Arduino project: %s" % arduino_project_dir)

        state = AppRPC.load_state()
        project_dir = os.path.join(state["storage"]["projectsDir"],
                                   time.strftime("%y%m%d-%H%M%S-") + board)
        if not os.path.isdir(project_dir):
            os.makedirs(project_dir)
        args = ["init", "--board", board]
        args.extend(["--project-option", "framework = arduino"])
        if use_arduino_libs:
            args.extend([
                "--project-option",
                "lib_extra_dirs = ~/Documents/Arduino/libraries"
            ])
        if (state["storage"]["coreCaller"] and state["storage"]["coreCaller"]
                in ProjectGenerator.get_supported_ides()):
            args.extend(["--ide", state["storage"]["coreCaller"]])
        await PIOCoreRPC.call(args,
                              options={
                                  "cwd": project_dir,
                                  "force_subprocess": True
                              })
        with fs.cd(project_dir):
            config = ProjectConfig()
            src_dir = config.get_optional_dir("src")
            if os.path.isdir(src_dir):
                fs.rmtree(src_dir)
            shutil.copytree(arduino_project_dir, src_dir, symlinks=True)
        return project_dir
Пример #8
0
    def import_pio(project_dir):
        if not project_dir or not is_platformio_project(project_dir):
            raise jsonrpc.exceptions.JSONRPCDispatchException(
                code=4001,
                message="Not an PlatformIO project: %s" % project_dir)
        new_project_dir = join(
            AppRPC.load_state()['storage']['projectsDir'],
            time.strftime("%y%m%d-%H%M%S-") + basename(project_dir))
        shutil.copytree(project_dir, new_project_dir)

        state = AppRPC.load_state()
        args = ["init"]
        if (state['storage']['coreCaller'] and state['storage']['coreCaller']
                in ProjectGenerator.get_supported_ides()):
            args.extend(["--ide", state['storage']['coreCaller']])
        d = PIOCoreRPC.call(args, options={"cwd": new_project_dir})
        d.addCallback(lambda _: new_project_dir)
        return d
Пример #9
0
    def import_arduino(self, board, use_arduino_libs, arduino_project_dir):
        board = str(board)
        if arduino_project_dir and PY2:
            arduino_project_dir = arduino_project_dir.encode(
                get_filesystem_encoding())
        # don't import PIO Project
        if is_platformio_project(arduino_project_dir):
            return arduino_project_dir

        is_arduino_project = any([
            os.path.isfile(
                os.path.join(
                    arduino_project_dir,
                    "%s.%s" % (os.path.basename(arduino_project_dir), ext),
                )) for ext in ("ino", "pde")
        ])
        if not is_arduino_project:
            raise jsonrpc.exceptions.JSONRPCDispatchException(
                code=4000,
                message="Not an Arduino project: %s" % arduino_project_dir)

        state = AppRPC.load_state()
        project_dir = os.path.join(state["storage"]["projectsDir"],
                                   time.strftime("%y%m%d-%H%M%S-") + board)
        if not os.path.isdir(project_dir):
            os.makedirs(project_dir)
        args = ["init", "--board", board]
        args.extend(["--project-option", "framework = arduino"])
        if use_arduino_libs:
            args.extend([
                "--project-option",
                "lib_extra_dirs = ~/Documents/Arduino/libraries"
            ])
        if (state["storage"]["coreCaller"] and state["storage"]["coreCaller"]
                in ProjectGenerator.get_supported_ides()):
            args.extend(["--ide", state["storage"]["coreCaller"]])
        d = PIOCoreRPC.call(args,
                            options={
                                "cwd": project_dir,
                                "force_subprocess": True
                            })
        d.addCallback(self._finalize_arduino_import, project_dir,
                      arduino_project_dir)
        return d
Пример #10
0
def dump_run_environment(options):
    non_sensitive_data = [
        "platform",
        "platform_packages",
        "framework",
        "board",
        "upload_protocol",
        "check_tool",
        "debug_tool",
        "monitor_filters",
    ]
    safe_options = {
        k: v
        for k, v in options.items() if k in non_sensitive_data
    }
    if is_platformio_project(os.getcwd()):
        phash = hashlib.sha1(hashlib_encode_data(app.get_cid()))
        safe_options["pid"] = phash.hexdigest()
    return json.dumps(safe_options, sort_keys=True, ensure_ascii=False)
Пример #11
0
def project_config(project_dir, json_output):
    if not is_platformio_project(project_dir):
        raise NotPlatformIOProjectError(project_dir)
    with fs.cd(project_dir):
        config = ProjectConfig.get_instance()
    if json_output:
        return click.echo(config.to_json())
    click.echo("Computed project configuration for %s" %
               click.style(project_dir, fg="cyan"))
    for section, options in config.as_tuple():
        click.secho(section, fg="cyan")
        click.echo("-" * len(section))
        click.echo(
            tabulate(
                [(name, "=",
                  "\n".join(value) if isinstance(value, list) else value)
                 for name, value in options],
                tablefmt="plain",
            ))
        click.echo()
    return None
Пример #12
0
    async def import_pio(project_dir):
        if not project_dir or not is_platformio_project(project_dir):
            raise JSONRPC20DispatchException(
                code=4001,
                message="Not an PlatformIO project: %s" % project_dir)
        new_project_dir = os.path.join(
            AppRPC.load_state()["storage"]["projectsDir"],
            time.strftime("%y%m%d-%H%M%S-") + os.path.basename(project_dir),
        )
        shutil.copytree(project_dir, new_project_dir, symlinks=True)

        state = AppRPC.load_state()
        args = ["init"]
        if (state["storage"]["coreCaller"] and state["storage"]["coreCaller"]
                in ProjectGenerator.get_supported_ides()):
            args.extend(["--ide", state["storage"]["coreCaller"]])
        await PIOCoreRPC.call(args,
                              options={
                                  "cwd": new_project_dir,
                                  "force_subprocess": True
                              })
        return new_project_dir
Пример #13
0
def cli(ctx, project_dir, project_conf, environment, verbose, interface,
        __unprocessed):
    # use env variables from Eclipse or CLion
    for sysenv in ("CWD", "PWD", "PLATFORMIO_PROJECT_DIR"):
        if is_platformio_project(project_dir):
            break
        if os.getenv(sysenv):
            project_dir = os.getenv(sysenv)

    with util.cd(project_dir):
        config = ProjectConfig.get_instance(
            project_conf or join(project_dir, "platformio.ini"))
        config.validate(envs=[environment] if environment else None)

        env_name = environment or helpers.get_default_debug_env(config)
        env_options = config.items(env=env_name, as_dict=True)
        if not set(env_options.keys()) >= set(["platform", "board"]):
            raise exception.ProjectEnvsNotAvailable()
        debug_options = helpers.validate_debug_options(ctx, env_options)
        assert debug_options

    if not interface:
        return helpers.predebug_project(ctx, project_dir, env_name, False,
                                        verbose)

    configuration = load_project_ide_data(project_dir, env_name)
    if not configuration:
        raise exception.DebugInvalidOptions(
            "Could not load debug configuration")

    if "--version" in __unprocessed:
        result = util.exec_command([configuration['gdb_path'], "--version"])
        if result['returncode'] == 0:
            return click.echo(result['out'])
        raise exception.PlatformioException("\n".join(
            [result['out'], result['err']]))

    try:
        util.ensure_udev_rules()
    except NameError:
        pass
    except exception.InvalidUdevRules as e:
        for line in str(e).split("\n") + [""]:
            click.echo(
                ('~"%s\\n"' if helpers.is_mi_mode(__unprocessed) else "%s") %
                line)

    debug_options['load_cmds'] = helpers.configure_esp32_load_cmds(
        debug_options, configuration)

    rebuild_prog = False
    preload = debug_options['load_cmds'] == ["preload"]
    load_mode = debug_options['load_mode']
    if load_mode == "always":
        rebuild_prog = (
            preload
            or not helpers.has_debug_symbols(configuration['prog_path']))
    elif load_mode == "modified":
        rebuild_prog = (
            helpers.is_prog_obsolete(configuration['prog_path'])
            or not helpers.has_debug_symbols(configuration['prog_path']))
    else:
        rebuild_prog = not isfile(configuration['prog_path'])

    if preload or (not rebuild_prog and load_mode != "always"):
        # don't load firmware through debug server
        debug_options['load_cmds'] = []

    if rebuild_prog:
        if helpers.is_mi_mode(__unprocessed):
            click.echo('~"Preparing firmware for debugging...\\n"')
            output = helpers.GDBBytesIO()
            with util.capture_std_streams(output):
                helpers.predebug_project(ctx, project_dir, env_name, preload,
                                         verbose)
            output.close()
        else:
            click.echo("Preparing firmware for debugging...")
            helpers.predebug_project(ctx, project_dir, env_name, preload,
                                     verbose)

        # save SHA sum of newly created prog
        if load_mode == "modified":
            helpers.is_prog_obsolete(configuration['prog_path'])

    if not isfile(configuration['prog_path']):
        raise exception.DebugInvalidOptions("Program/firmware is missed")

    # run debugging client
    inject_contrib_pysite()
    from platformio.commands.debug.client import GDBClient, reactor

    client = GDBClient(project_dir, __unprocessed, debug_options, env_options)
    client.spawn(configuration['gdb_path'], configuration['prog_path'])

    signal.signal(signal.SIGINT, lambda *args, **kwargs: None)
    reactor.run()

    return True
Пример #14
0
def cli(ctx, project_dir, project_conf, environment, verbose, interface,
        __unprocessed):
    app.set_session_var("custom_project_conf", project_conf)

    # use env variables from Eclipse or CLion
    for sysenv in ("CWD", "PWD", "PLATFORMIO_PROJECT_DIR"):
        if is_platformio_project(project_dir):
            break
        if os.getenv(sysenv):
            project_dir = os.getenv(sysenv)

    with fs.cd(project_dir):
        config = ProjectConfig.get_instance(project_conf)
        config.validate(envs=[environment] if environment else None)

        env_name = environment or helpers.get_default_debug_env(config)
        env_options = config.items(env=env_name, as_dict=True)
        if not set(env_options.keys()) >= set(["platform", "board"]):
            raise ProjectEnvsNotAvailableError()
        debug_options = helpers.validate_debug_options(ctx, env_options)
        assert debug_options

    if not interface:
        return helpers.predebug_project(ctx, project_dir, env_name, False,
                                        verbose)

    configuration = load_project_ide_data(project_dir, env_name)
    if not configuration:
        raise DebugInvalidOptionsError("Could not load debug configuration")

    if "--version" in __unprocessed:
        result = proc.exec_command([configuration["gdb_path"], "--version"])
        if result["returncode"] == 0:
            return click.echo(result["out"])
        raise exception.PlatformioException("\n".join(
            [result["out"], result["err"]]))

    try:
        fs.ensure_udev_rules()
    except exception.InvalidUdevRules as e:
        click.echo(
            helpers.escape_gdbmi_stream("~",
                                        str(e) + "\n")
            if helpers.is_gdbmi_mode() else str(e) + "\n",
            nl=False,
        )

    debug_options["load_cmds"] = helpers.configure_esp32_load_cmds(
        debug_options, configuration)

    rebuild_prog = False
    preload = debug_options["load_cmds"] == ["preload"]
    load_mode = debug_options["load_mode"]
    if load_mode == "always":
        rebuild_prog = preload or not helpers.has_debug_symbols(
            configuration["prog_path"])
    elif load_mode == "modified":
        rebuild_prog = helpers.is_prog_obsolete(
            configuration["prog_path"]) or not helpers.has_debug_symbols(
                configuration["prog_path"])
    else:
        rebuild_prog = not isfile(configuration["prog_path"])

    if preload or (not rebuild_prog and load_mode != "always"):
        # don't load firmware through debug server
        debug_options["load_cmds"] = []

    if rebuild_prog:
        if helpers.is_gdbmi_mode():
            click.echo(
                helpers.escape_gdbmi_stream(
                    "~", "Preparing firmware for debugging...\n"),
                nl=False,
            )
            stream = helpers.GDBMIConsoleStream()
            with util.capture_std_streams(stream):
                helpers.predebug_project(ctx, project_dir, env_name, preload,
                                         verbose)
            stream.close()
        else:
            click.echo("Preparing firmware for debugging...")
            helpers.predebug_project(ctx, project_dir, env_name, preload,
                                     verbose)

        # save SHA sum of newly created prog
        if load_mode == "modified":
            helpers.is_prog_obsolete(configuration["prog_path"])

    if not isfile(configuration["prog_path"]):
        raise DebugInvalidOptionsError("Program/firmware is missed")

    # run debugging client
    inject_contrib_pysite()

    # pylint: disable=import-outside-toplevel
    from platformio.commands.debug.process.client import GDBClient, reactor

    client = GDBClient(project_dir, __unprocessed, debug_options, env_options)
    client.spawn(configuration["gdb_path"], configuration["prog_path"])

    signal.signal(signal.SIGINT, lambda *args, **kwargs: None)
    reactor.run()

    return True
Пример #15
0
def cli(
        ctx,  # pylint: disable=R0913
        project_dir,
        board,
        ide,
        project_option,
        env_prefix,
        silent):
    if not silent:
        if project_dir == getcwd():
            click.secho("\nThe current working directory",
                        fg="yellow",
                        nl=False)
            click.secho(" %s " % project_dir, fg="cyan", nl=False)
            click.secho("will be used for the project.", fg="yellow")
            click.echo("")

        click.echo("The next files/directories have been created in %s" %
                   click.style(project_dir, fg="cyan"))
        click.echo("%s - Put project header files here" %
                   click.style("include", fg="cyan"))
        click.echo("%s - Put here project specific (private) libraries" %
                   click.style("lib", fg="cyan"))
        click.echo("%s - Put project source files here" %
                   click.style("src", fg="cyan"))
        click.echo("%s - Project Configuration File" %
                   click.style("platformio.ini", fg="cyan"))

    is_new_project = not is_platformio_project(project_dir)
    if is_new_project:
        init_base_project(project_dir)

    if board:
        fill_project_envs(ctx, project_dir, board, project_option, env_prefix,
                          ide is not None)

    if ide:
        pg = ProjectGenerator(project_dir, ide, board)
        pg.generate()

    if is_new_project:
        init_ci_conf(project_dir)
        init_cvs_ignore(project_dir)

    if silent:
        return

    if ide:
        click.secho(
            "\nProject has been successfully %s including configuration files "
            "for `%s` IDE." %
            ("initialized" if is_new_project else "updated", ide),
            fg="green")
    else:
        click.secho(
            "\nProject has been successfully %s! Useful commands:\n"
            "`pio run` - process/build project from the current directory\n"
            "`pio run --target upload` or `pio run -t upload` "
            "- upload firmware to a target\n"
            "`pio run --target clean` - clean project (remove compiled files)"
            "\n`pio run --help` - additional information" %
            ("initialized" if is_new_project else "updated"),
            fg="green")
Пример #16
0
    def parse_examples_from_dir(package_dir):
        assert os.path.isdir(package_dir)
        examples_dir = os.path.join(package_dir, "examples")
        if not os.path.isdir(examples_dir):
            examples_dir = os.path.join(package_dir, "Examples")
            if not os.path.isdir(examples_dir):
                return None

        allowed_exts = (
            ".c",
            ".cc",
            ".cpp",
            ".h",
            ".hpp",
            ".asm",
            ".ASM",
            ".s",
            ".S",
            ".ino",
            ".pde",
        )

        result = {}
        last_pio_project = None
        for root, _, files in os.walk(examples_dir):
            # skip hidden files, symlinks, and folders
            files = [
                f for f in files if not f.startswith(".")
                and not os.path.islink(os.path.join(root, f))
            ]
            if os.path.basename(root).startswith(".") or not files:
                continue

            if is_platformio_project(root):
                last_pio_project = root
                result[last_pio_project] = dict(
                    name=os.path.relpath(root, examples_dir),
                    base=os.path.relpath(root, package_dir),
                    files=files,
                )
                continue
            if last_pio_project:
                if root.startswith(last_pio_project):
                    result[last_pio_project]["files"].extend([
                        os.path.relpath(os.path.join(root, f),
                                        last_pio_project) for f in files
                    ])
                    continue
                last_pio_project = None

            matched_files = [f for f in files if f.endswith(allowed_exts)]
            if not matched_files:
                continue
            result[root] = dict(
                name="Examples" if root == examples_dir else os.path.relpath(
                    root, examples_dir),
                base=os.path.relpath(root, package_dir),
                files=matched_files,
            )

        result = list(result.values())

        # normalize example names
        for item in result:
            item["name"] = item["name"].replace(os.path.sep, "/")
            item["name"] = re.sub(r"[^a-z\d\d\-\_/]+",
                                  "_",
                                  item["name"],
                                  flags=re.I)

        return result or None
Пример #17
0
def project_init(
    ctx,  # pylint: disable=R0913
    project_dir,
    board,
    ide,
    environment,
    project_option,
    env_prefix,
    silent,
):
    if not silent:
        if project_dir == os.getcwd():
            click.secho("\nThe current working directory ",
                        fg="yellow",
                        nl=False)
            try:
                click.secho(project_dir, fg="cyan", nl=False)
            except UnicodeEncodeError:
                click.secho(json.dumps(project_dir), fg="cyan", nl=False)
            click.secho(" will be used for the project.", fg="yellow")
            click.echo("")

        click.echo("The next files/directories have been created in ",
                   nl=False)
        try:
            click.secho(project_dir, fg="cyan")
        except UnicodeEncodeError:
            click.secho(json.dumps(project_dir), fg="cyan")
        click.echo("%s - Put project header files here" %
                   click.style("include", fg="cyan"))
        click.echo("%s - Put here project specific (private) libraries" %
                   click.style("lib", fg="cyan"))
        click.echo("%s - Put project source files here" %
                   click.style("src", fg="cyan"))
        click.echo("%s - Project Configuration File" %
                   click.style("platformio.ini", fg="cyan"))

    is_new_project = not is_platformio_project(project_dir)
    if is_new_project:
        init_base_project(project_dir)

    if environment:
        update_project_env(project_dir, environment, project_option)
    elif board:
        update_board_envs(ctx, project_dir, board, project_option, env_prefix,
                          ide is not None)

    if ide:
        with fs.cd(project_dir):
            config = ProjectConfig.get_instance(
                os.path.join(project_dir, "platformio.ini"))
        config.validate()
        pg = ProjectGenerator(config, environment
                              or get_best_envname(config, board), ide)
        pg.generate()

    if is_new_project:
        init_cvs_ignore(project_dir)

    if silent:
        return

    if ide:
        click.secho(
            "\nProject has been successfully %s including configuration files "
            "for `%s` IDE." %
            ("initialized" if is_new_project else "updated", ide),
            fg="green",
        )
    else:
        click.secho(
            "\nProject has been successfully %s! Useful commands:\n"
            "`pio run` - process/build project from the current directory\n"
            "`pio run --target upload` or `pio run -t upload` "
            "- upload firmware to a target\n"
            "`pio run --target clean` - clean project (remove compiled files)"
            "\n`pio run --help` - additional information" %
            ("initialized" if is_new_project else "updated"),
            fg="green",
        )