forked from platformio/platformio-core
Introduced a new --sample-code
option to the pio project init
command
This commit is contained in:
@ -18,10 +18,11 @@ PlatformIO Core 6
|
||||
6.1.7 (2023-??-??)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Implemented a new feature to store device monitor logs in the project's ``logs`` folder, making it easier to access and review device monitor logs for your projects (`issue #4596 <https://github.com/platformio/platformio-core/issues/4596>`_)
|
||||
* Introduced a new ``--sample-code`` option to the `pio project init <https://docs.platformio.org/en/latest/core/userguide/project/cmd_init.html>`__ command, which allows users to include sample code in the newly created project
|
||||
* Added validation for `project working environment names <https://docs.platformio.org/en/latest/projectconf/sections/env/index.html#working-env-name>`__ to ensure that they only contain lowercase letters ``a-z``, numbers ``0-9``, and special characters ``_`` (underscore) and ``-`` (hyphen)
|
||||
* Added the ability to show a detailed library dependency tree only in `verbose mode <https://docs.platformio.org/en/latest/core/userguide/cmd_run.html#cmdoption-pio-run-v>`__, which can help you understand the relationship between libraries and troubleshoot issues more effectively (`issue #4517 <https://github.com/platformio/platformio-core/issues/4517>`_)
|
||||
* Added the ability to run only the `device monitor <https://docs.platformio.org/en/latest/core/userguide/device/cmd_monitor.html>`__ when using the `pio run -t monitor <https://docs.platformio.org/en/latest/core/userguide/cmd_run.html>`__ command, saving you time and resources by skipping the build process
|
||||
* Added validation for `project working environment names <https://docs.platformio.org/en/latest/projectconf/sections/env/index.html#working-env-name>`__ to ensure that they only contain lowercase letters ``a-z``, numbers ``0-9``, and special characters ``_`` (underscore) and ``-`` (hyphen)
|
||||
* Implemented a new feature to store device monitor logs in the project's ``logs`` folder, making it easier to access and review device monitor logs for your projects (`issue #4596 <https://github.com/platformio/platformio-core/issues/4596>`_)
|
||||
* Improved support for projects located on Windows network drives, including Network Shared Folder, Dropbox, OneDrive, Google Drive, and other similar services (`issue #3417 <https://github.com/platformio/platformio-core/issues/3417>`_)
|
||||
* Improved source file filtering functionality for the `Static Code Analysis <https://docs.platformio.org/en/latest/advanced/static-code-analysis/index.html>`__ feature, making it easier to analyze only the code you need to
|
||||
* Upgraded the build engine to the latest version of SCons (4.5.2) to improve build performance, reliability, and compatibility with other tools and systems (`release notes <https://github.com/SCons/scons/releases/tag/4.5.2>`__)
|
||||
|
2
docs
2
docs
Submodule docs updated: 54a797fb54...89233bd239
@ -107,8 +107,8 @@ def cli( # pylint: disable=too-many-arguments, too-many-branches
|
||||
ctx.invoke(
|
||||
project_init_cmd,
|
||||
project_dir=build_dir,
|
||||
board=board,
|
||||
project_option=project_option,
|
||||
boards=board,
|
||||
project_options=project_option,
|
||||
)
|
||||
|
||||
# process project
|
||||
|
@ -18,7 +18,7 @@ import time
|
||||
|
||||
from ajsonrpc.core import JSONRPC20DispatchException
|
||||
|
||||
from platformio import exception, fs
|
||||
from platformio import app, exception, fs
|
||||
from platformio.home.rpc.handlers.app import AppRPC
|
||||
from platformio.home.rpc.handlers.base import BaseRPCHandler
|
||||
from platformio.home.rpc.handlers.piocore import PIOCoreRPC
|
||||
@ -185,83 +185,17 @@ class ProjectRPC(BaseRPCHandler):
|
||||
|
||||
async def init(self, board, framework, project_dir):
|
||||
assert project_dir
|
||||
state = AppRPC.load_state()
|
||||
if not os.path.isdir(project_dir):
|
||||
os.makedirs(project_dir)
|
||||
args = ["init", "--board", board]
|
||||
args = ["init", "--board", board, "--sample-code"]
|
||||
if framework:
|
||||
args.extend(["--project-option", "framework = %s" % framework])
|
||||
if (
|
||||
state["storage"]["coreCaller"]
|
||||
and state["storage"]["coreCaller"] in ProjectGenerator.get_supported_ides()
|
||||
):
|
||||
args.extend(["--ide", state["storage"]["coreCaller"]])
|
||||
ide = app.get_session_var("caller_id")
|
||||
if ide in ProjectGenerator.get_supported_ides():
|
||||
args.extend(["--ide", ide])
|
||||
await PIOCoreRPC.call(
|
||||
args, options={"cwd": project_dir, "force_subprocess": True}
|
||||
)
|
||||
return self._generate_project_main(project_dir, board, framework)
|
||||
|
||||
@staticmethod
|
||||
def _generate_project_main(project_dir, board, framework):
|
||||
main_content = None
|
||||
if framework == "arduino":
|
||||
main_content = "\n".join(
|
||||
[
|
||||
"#include <Arduino.h>",
|
||||
"",
|
||||
"void setup() {",
|
||||
" // put your setup code here, to run once:",
|
||||
"}",
|
||||
"",
|
||||
"void loop() {",
|
||||
" // put your main code here, to run repeatedly:",
|
||||
"}",
|
||||
"",
|
||||
]
|
||||
)
|
||||
elif framework == "mbed":
|
||||
main_content = "\n".join(
|
||||
[
|
||||
"#include <mbed.h>",
|
||||
"",
|
||||
"int main() {",
|
||||
"",
|
||||
" // put your setup code here, to run once:",
|
||||
"",
|
||||
" while(1) {",
|
||||
" // put your main code here, to run repeatedly:",
|
||||
" }",
|
||||
"}",
|
||||
"",
|
||||
]
|
||||
)
|
||||
if not main_content:
|
||||
return project_dir
|
||||
|
||||
is_cpp_project = True
|
||||
pm = PlatformPackageManager()
|
||||
try:
|
||||
board = pm.board_config(board)
|
||||
platforms = board.get("platforms", board.get("platform"))
|
||||
if not isinstance(platforms, list):
|
||||
platforms = [platforms]
|
||||
c_based_platforms = ["intel_mcs51", "ststm8"]
|
||||
is_cpp_project = not set(platforms) & set(c_based_platforms)
|
||||
except exception.PlatformioException:
|
||||
pass
|
||||
|
||||
with fs.cd(project_dir):
|
||||
config = ProjectConfig()
|
||||
src_dir = config.get("platformio", "src_dir")
|
||||
main_path = os.path.join(
|
||||
src_dir, "main.%s" % ("cpp" if is_cpp_project else "c")
|
||||
)
|
||||
if os.path.isfile(main_path):
|
||||
return project_dir
|
||||
if not os.path.isdir(src_dir):
|
||||
os.makedirs(src_dir)
|
||||
with open(main_path, mode="w", encoding="utf8") as fp:
|
||||
fp.write(main_content.strip())
|
||||
return project_dir
|
||||
|
||||
@staticmethod
|
||||
@ -297,11 +231,9 @@ class ProjectRPC(BaseRPCHandler):
|
||||
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"]])
|
||||
ide = app.get_session_var("caller_id")
|
||||
if ide in ProjectGenerator.get_supported_ides():
|
||||
args.extend(["--ide", ide])
|
||||
await PIOCoreRPC.call(
|
||||
args, options={"cwd": project_dir, "force_subprocess": True}
|
||||
)
|
||||
@ -325,13 +257,10 @@ class ProjectRPC(BaseRPCHandler):
|
||||
)
|
||||
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"]])
|
||||
ide = app.get_session_var("caller_id")
|
||||
if ide in ProjectGenerator.get_supported_ides():
|
||||
args.extend(["--ide", ide])
|
||||
await PIOCoreRPC.call(
|
||||
args, options={"cwd": new_project_dir, "force_subprocess": True}
|
||||
)
|
||||
|
@ -207,6 +207,15 @@ class PlatformBase( # pylint: disable=too-many-instance-attributes,too-many-pub
|
||||
def configure_debug_session(self, debug_config):
|
||||
raise NotImplementedError
|
||||
|
||||
def generate_sample_code(self, project_config, environment):
|
||||
raise NotImplementedError
|
||||
|
||||
def on_installed(self):
|
||||
pass
|
||||
|
||||
def on_uninstalled(self):
|
||||
pass
|
||||
|
||||
def get_lib_storages(self):
|
||||
storages = {}
|
||||
for opts in (self.frameworks or {}).values():
|
||||
@ -227,9 +236,3 @@ class PlatformBase( # pylint: disable=too-many-instance-attributes,too-many-pub
|
||||
storages[libcore_dir] = "%s-core-%s" % (opts["package"], item)
|
||||
|
||||
return [dict(name=name, path=path) for path, name in storages.items()]
|
||||
|
||||
def on_installed(self):
|
||||
pass
|
||||
|
||||
def on_uninstalled(self):
|
||||
pass
|
||||
|
@ -24,12 +24,14 @@ from platformio import fs
|
||||
from platformio.package.commands.install import install_project_dependencies
|
||||
from platformio.package.manager.platform import PlatformPackageManager
|
||||
from platformio.platform.exception import UnknownBoard
|
||||
from platformio.platform.factory import PlatformFactory
|
||||
from platformio.project.config import ProjectConfig
|
||||
from platformio.project.helpers import is_platformio_project
|
||||
from platformio.project.integration.generator import ProjectGenerator
|
||||
from platformio.project.options import ProjectOptions
|
||||
|
||||
|
||||
def validate_boards(ctx, param, value): # pylint: disable=W0613
|
||||
def validate_boards(ctx, param, value): # pylint: disable=unused-argument
|
||||
pm = PlatformPackageManager()
|
||||
for id_ in value:
|
||||
try:
|
||||
@ -49,21 +51,31 @@ def validate_boards(ctx, param, value): # pylint: disable=W0613
|
||||
default=os.getcwd,
|
||||
type=click.Path(exists=True, file_okay=False, dir_okay=True, writable=True),
|
||||
)
|
||||
@click.option("-b", "--board", multiple=True, metavar="ID", callback=validate_boards)
|
||||
@click.option(
|
||||
"-b", "--board", "boards", multiple=True, metavar="ID", callback=validate_boards
|
||||
)
|
||||
@click.option("--ide", type=click.Choice(ProjectGenerator.get_supported_ides()))
|
||||
@click.option("-e", "--environment", help="Update existing environment")
|
||||
@click.option("-O", "--project-option", multiple=True)
|
||||
@click.option("--env-prefix", default="")
|
||||
@click.option(
|
||||
"-O",
|
||||
"--project-option",
|
||||
"project_options",
|
||||
multiple=True,
|
||||
help="A `name=value` pair",
|
||||
)
|
||||
@click.option("--sample-code", is_flag=True)
|
||||
@click.option("--no-install-dependencies", is_flag=True)
|
||||
@click.option("--env-prefix", default="")
|
||||
@click.option("-s", "--silent", is_flag=True)
|
||||
def project_init_cmd(
|
||||
project_dir,
|
||||
board,
|
||||
boards,
|
||||
ide,
|
||||
environment,
|
||||
project_option,
|
||||
env_prefix,
|
||||
project_options,
|
||||
sample_code,
|
||||
no_install_dependencies,
|
||||
env_prefix,
|
||||
silent,
|
||||
):
|
||||
is_new_project = not is_platformio_project(project_dir)
|
||||
@ -72,23 +84,23 @@ def project_init_cmd(
|
||||
print_header(project_dir)
|
||||
init_base_project(project_dir)
|
||||
|
||||
if environment:
|
||||
update_project_env(project_dir, environment, project_option)
|
||||
elif board:
|
||||
update_board_envs(project_dir, board, project_option, env_prefix)
|
||||
|
||||
with fs.cd(project_dir):
|
||||
if environment:
|
||||
update_project_env(environment, project_options)
|
||||
elif boards:
|
||||
update_board_envs(project_dir, boards, project_options, env_prefix)
|
||||
|
||||
generator = None
|
||||
config = ProjectConfig.get_instance(os.path.join(project_dir, "platformio.ini"))
|
||||
if ide:
|
||||
config.validate()
|
||||
# init generator and pick the best env if user didn't specify
|
||||
generator = ProjectGenerator(config, environment, ide, board)
|
||||
generator = ProjectGenerator(config, environment, ide, boards)
|
||||
if not environment:
|
||||
environment = generator.env_name
|
||||
|
||||
# resolve project dependencies
|
||||
if not no_install_dependencies and (environment or board):
|
||||
if not no_install_dependencies and (environment or boards):
|
||||
install_project_dependencies(
|
||||
options=dict(
|
||||
project_dir=project_dir,
|
||||
@ -97,6 +109,9 @@ def project_init_cmd(
|
||||
)
|
||||
)
|
||||
|
||||
if environment and sample_code:
|
||||
init_sample_code(config, environment)
|
||||
|
||||
if generator:
|
||||
if not silent:
|
||||
click.echo(
|
||||
@ -104,8 +119,8 @@ def project_init_cmd(
|
||||
)
|
||||
generator.generate()
|
||||
|
||||
if is_new_project:
|
||||
init_cvs_ignore(project_dir)
|
||||
if is_new_project:
|
||||
init_cvs_ignore()
|
||||
|
||||
if not silent:
|
||||
print_footer(is_new_project)
|
||||
@ -289,15 +304,15 @@ More information about PlatformIO Unit Testing:
|
||||
)
|
||||
|
||||
|
||||
def init_cvs_ignore(project_dir):
|
||||
conf_path = os.path.join(project_dir, ".gitignore")
|
||||
def init_cvs_ignore():
|
||||
conf_path = ".gitignore"
|
||||
if os.path.isfile(conf_path):
|
||||
return
|
||||
with open(conf_path, mode="w", encoding="utf8") as fp:
|
||||
fp.write(".pio\n")
|
||||
|
||||
|
||||
def update_board_envs(project_dir, board_ids, project_option, env_prefix):
|
||||
def update_board_envs(project_dir, boards, extra_project_options, env_prefix):
|
||||
config = ProjectConfig(
|
||||
os.path.join(project_dir, "platformio.ini"), parse_extra=False
|
||||
)
|
||||
@ -309,7 +324,7 @@ def update_board_envs(project_dir, board_ids, project_option, env_prefix):
|
||||
|
||||
pm = PlatformPackageManager()
|
||||
modified = False
|
||||
for id_ in board_ids:
|
||||
for id_ in boards:
|
||||
board_config = pm.board_config(id_)
|
||||
if id_ in used_boards:
|
||||
continue
|
||||
@ -322,7 +337,7 @@ def update_board_envs(project_dir, board_ids, project_option, env_prefix):
|
||||
if frameworks:
|
||||
envopts["framework"] = frameworks[0]
|
||||
|
||||
for item in project_option:
|
||||
for item in extra_project_options:
|
||||
if "=" not in item:
|
||||
continue
|
||||
_name, _value = item.split("=", 1)
|
||||
@ -338,21 +353,74 @@ def update_board_envs(project_dir, board_ids, project_option, env_prefix):
|
||||
config.save()
|
||||
|
||||
|
||||
def update_project_env(project_dir, environment, project_option):
|
||||
if not project_option:
|
||||
def update_project_env(environment, extra_project_options=None):
|
||||
if not extra_project_options:
|
||||
return
|
||||
env_section = "env:%s" % environment
|
||||
option_to_sections = {"platformio": [], env_section: []}
|
||||
for item in extra_project_options:
|
||||
assert "=" in item
|
||||
name, value = item.split("=", 1)
|
||||
name = name.strip()
|
||||
destination = env_section
|
||||
for option in ProjectOptions.values():
|
||||
if option.scope in option_to_sections and option.name == name:
|
||||
destination = option.scope
|
||||
break
|
||||
option_to_sections[destination].append((name, value.strip()))
|
||||
|
||||
config = ProjectConfig(
|
||||
os.path.join(project_dir, "platformio.ini"), parse_extra=False
|
||||
"platformio.ini", parse_extra=False, expand_interpolations=False
|
||||
)
|
||||
|
||||
section = "env:%s" % environment
|
||||
if not config.has_section(section):
|
||||
config.add_section(section)
|
||||
|
||||
for item in project_option:
|
||||
if "=" not in item:
|
||||
continue
|
||||
_name, _value = item.split("=", 1)
|
||||
config.set(section, _name.strip(), _value.strip())
|
||||
for section, options in option_to_sections.items():
|
||||
if not config.has_section(section):
|
||||
config.add_section(section)
|
||||
for name, value in options:
|
||||
config.set(section, name, value)
|
||||
|
||||
config.save()
|
||||
|
||||
|
||||
def init_sample_code(config, environment):
|
||||
platform_spec = config.get(f"env:{environment}", "platform", None)
|
||||
if not platform_spec:
|
||||
return None
|
||||
p = PlatformFactory.new(platform_spec)
|
||||
try:
|
||||
return p.generate_sample_code(config, environment)
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
framework = config.get(f"env:{environment}", "framework", None)
|
||||
if framework != ["arduino"]:
|
||||
return None
|
||||
main_content = """
|
||||
#include <Arduino.h>
|
||||
|
||||
// put function declarations here:
|
||||
int myFunction(int, int);
|
||||
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
int result = myFunction(2, 3);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// put your main code here, to run repeatedly:
|
||||
}
|
||||
|
||||
// put function definitions here:
|
||||
int myFunction(int x, int y) {
|
||||
return x + y;
|
||||
}
|
||||
"""
|
||||
is_cpp_project = p.name not in ["intel_mcs51", "ststm8"]
|
||||
src_dir = config.get("platformio", "src_dir")
|
||||
main_path = os.path.join(src_dir, "main.%s" % ("cpp" if is_cpp_project else "c"))
|
||||
if os.path.isfile(main_path):
|
||||
return None
|
||||
if not os.path.isdir(src_dir):
|
||||
os.makedirs(src_dir)
|
||||
with open(main_path, mode="w", encoding="utf8") as fp:
|
||||
fp.write(main_content.strip())
|
||||
return True
|
||||
|
@ -25,28 +25,28 @@ from platformio.project.helpers import load_build_metadata
|
||||
|
||||
|
||||
class ProjectGenerator:
|
||||
def __init__(self, config, env_name, ide, board_ids=None):
|
||||
def __init__(self, config, env_name, ide, boards=None):
|
||||
self.config = config
|
||||
self.project_dir = os.path.dirname(config.path)
|
||||
self.forced_env_name = env_name
|
||||
self.env_name = str(env_name or self.get_best_envname(board_ids))
|
||||
self.env_name = str(env_name or self.get_best_envname(boards))
|
||||
self.ide = str(ide)
|
||||
|
||||
def get_best_envname(self, board_ids=None):
|
||||
def get_best_envname(self, boards=None):
|
||||
envname = None
|
||||
default_envs = self.config.default_envs()
|
||||
if default_envs:
|
||||
envname = default_envs[0]
|
||||
if not board_ids:
|
||||
if not boards:
|
||||
return envname
|
||||
|
||||
for env in self.config.envs():
|
||||
if not board_ids:
|
||||
if not boards:
|
||||
return env
|
||||
if not envname:
|
||||
envname = env
|
||||
items = self.config.items(env=env, as_dict=True)
|
||||
if "board" in items and items.get("board") in board_ids:
|
||||
if "board" in items and items.get("board") in boards:
|
||||
return env
|
||||
return envname
|
||||
|
||||
|
Reference in New Issue
Block a user