Added a new "-e, --environment" option to "platformio project init" command

This commit is contained in:
Ivan Kravets
2020-06-12 23:47:12 +03:00
parent fdb83c24be
commit 28d9f25f9a
6 changed files with 83 additions and 51 deletions

View File

@ -17,6 +17,7 @@ PlatformIO Core 4
* Added support for `custom targets <https://docs.platformio.org/page/projectconf/advanced_scripting.html#custom-targets>`__ (user cases: command shortcuts, pre/post processing based on dependencies, custom command launcher with options, etc.) * Added support for `custom targets <https://docs.platformio.org/page/projectconf/advanced_scripting.html#custom-targets>`__ (user cases: command shortcuts, pre/post processing based on dependencies, custom command launcher with options, etc.)
* Added support for "globstar/`**`" (recursive) pattern for the different commands and configuration options (`platformio ci <https://docs.platformio.org/page/core/userguide/cmd_ci.html>`__, `src_filter <https://docs.platformio.org/page/projectconf/section_env_build.html#src-filter>`__, `check_patterns <https://docs.platformio.org/page/projectconf/section_env_check.html#check-patterns>`__, `library.json > srcFilter <https://docs.platformio.org/page/librarymanager/config.html#srcfilter>`__). Python 3.5+ is required. * Added support for "globstar/`**`" (recursive) pattern for the different commands and configuration options (`platformio ci <https://docs.platformio.org/page/core/userguide/cmd_ci.html>`__, `src_filter <https://docs.platformio.org/page/projectconf/section_env_build.html#src-filter>`__, `check_patterns <https://docs.platformio.org/page/projectconf/section_env_check.html#check-patterns>`__, `library.json > srcFilter <https://docs.platformio.org/page/librarymanager/config.html#srcfilter>`__). Python 3.5+ is required.
* Added a new ``-e, --environment`` option to `platformio project init <https://docs.platformio.org/page/core/userguide/project/cmd_init.html#cmdoption-platformio-project-init-e>`__ command that helps to update a PlatformIO project using existing environment
* Fixed an issue with PIO Unit Testing when running multiple environments (`issue #3523 <https://github.com/platformio/platformio-core/issues/3523>`_) * Fixed an issue with PIO Unit Testing when running multiple environments (`issue #3523 <https://github.com/platformio/platformio-core/issues/3523>`_)
4.3.4 (2020-05-23) 4.3.4 (2020-05-23)

2
docs

Submodule docs updated: ec54ae9917...2178afaf33

View File

@ -93,6 +93,7 @@ def validate_boards(ctx, param, value): # pylint: disable=W0613
) )
@click.option("-b", "--board", multiple=True, metavar="ID", callback=validate_boards) @click.option("-b", "--board", multiple=True, metavar="ID", callback=validate_boards)
@click.option("--ide", type=click.Choice(ProjectGenerator.get_supported_ides())) @click.option("--ide", type=click.Choice(ProjectGenerator.get_supported_ides()))
@click.option("-e", "--environment", help="Update using existing environment")
@click.option("-O", "--project-option", multiple=True) @click.option("-O", "--project-option", multiple=True)
@click.option("--env-prefix", default="") @click.option("--env-prefix", default="")
@click.option("-s", "--silent", is_flag=True) @click.option("-s", "--silent", is_flag=True)
@ -102,6 +103,7 @@ def project_init(
project_dir, project_dir,
board, board,
ide, ide,
environment,
project_option, project_option,
env_prefix, env_prefix,
silent, silent,
@ -139,7 +141,11 @@ def project_init(
) )
if ide: if ide:
pg = ProjectGenerator(project_dir, ide, board) 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() pg.generate()
if is_new_project: if is_new_project:
@ -444,3 +450,23 @@ def _install_dependent_platforms(ctx, platforms):
ctx.invoke( ctx.invoke(
cli_platform_install, platforms=list(set(platforms) - set(installed_platforms)) cli_platform_install, platforms=list(set(platforms) - set(installed_platforms))
) )
def get_best_envname(config, board_ids=None):
envname = None
default_envs = config.default_envs()
if default_envs:
envname = default_envs[0]
if not board_ids:
return envname
for env in config.envs():
if not board_ids:
return env
if not envname:
envname = env
items = config.items(env=env, as_dict=True)
if "board" in items and items.get("board") in board_ids:
return env
return envname

View File

@ -15,47 +15,31 @@
import codecs import codecs
import os import os
import sys import sys
from os.path import basename, isdir, isfile, join, realpath, relpath
import bottle import bottle
from platformio import fs, util from platformio import fs, util
from platformio.proc import where_is_program from platformio.proc import where_is_program
from platformio.project.config import ProjectConfig
from platformio.project.helpers import load_project_ide_data from platformio.project.helpers import load_project_ide_data
class ProjectGenerator(object): class ProjectGenerator(object):
def __init__(self, project_dir, ide, boards): def __init__(self, config, env_name, ide):
self.config = ProjectConfig.get_instance(join(project_dir, "platformio.ini")) self.config = config
self.config.validate() self.project_dir = os.path.dirname(config.path)
self.project_dir = project_dir self.env_name = str(env_name)
self.ide = str(ide) self.ide = str(ide)
self.env_name = str(self.get_best_envname(boards))
@staticmethod @staticmethod
def get_supported_ides(): def get_supported_ides():
tpls_dir = join(fs.get_source_dir(), "ide", "tpls") tpls_dir = os.path.join(fs.get_source_dir(), "ide", "tpls")
return sorted([d for d in os.listdir(tpls_dir) if isdir(join(tpls_dir, d))]) return sorted(
[
def get_best_envname(self, boards=None): d
envname = None for d in os.listdir(tpls_dir)
default_envs = self.config.default_envs() if os.path.isdir(os.path.join(tpls_dir, d))
if default_envs: ]
envname = default_envs[0] )
if not boards:
return envname
for env in self.config.envs():
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 boards:
return env
return envname
@staticmethod @staticmethod
def filter_includes(includes_map, ignore_scopes=None, to_unix_path=True): def filter_includes(includes_map, ignore_scopes=None, to_unix_path=True):
@ -75,12 +59,12 @@ class ProjectGenerator(object):
tpl_vars = { tpl_vars = {
"config": self.config, "config": self.config,
"systype": util.get_systype(), "systype": util.get_systype(),
"project_name": basename(self.project_dir), "project_name": os.path.basename(self.project_dir),
"project_dir": self.project_dir, "project_dir": self.project_dir,
"env_name": self.env_name, "env_name": self.env_name,
"user_home_dir": realpath(fs.expanduser("~")), "user_home_dir": os.path.realpath(fs.expanduser("~")),
"platformio_path": sys.argv[0] "platformio_path": sys.argv[0]
if isfile(sys.argv[0]) if os.path.isfile(sys.argv[0])
else where_is_program("platformio"), else where_is_program("platformio"),
"env_path": os.getenv("PATH"), "env_path": os.getenv("PATH"),
"env_pathsep": os.pathsep, "env_pathsep": os.pathsep,
@ -97,7 +81,7 @@ class ProjectGenerator(object):
"src_files": self.get_src_files(), "src_files": self.get_src_files(),
"project_src_dir": self.config.get_optional_dir("src"), "project_src_dir": self.config.get_optional_dir("src"),
"project_lib_dir": self.config.get_optional_dir("lib"), "project_lib_dir": self.config.get_optional_dir("lib"),
"project_libdeps_dir": join( "project_libdeps_dir": os.path.join(
self.config.get_optional_dir("libdeps"), self.env_name self.config.get_optional_dir("libdeps"), self.env_name
), ),
} }
@ -120,12 +104,12 @@ class ProjectGenerator(object):
with fs.cd(self.project_dir): with fs.cd(self.project_dir):
for root, _, files in os.walk(self.config.get_optional_dir("src")): for root, _, files in os.walk(self.config.get_optional_dir("src")):
for f in files: for f in files:
result.append(relpath(join(root, f))) result.append(os.path.relpath(os.path.join(root, f)))
return result return result
def get_tpls(self): def get_tpls(self):
tpls = [] tpls = []
tpls_dir = join(fs.get_source_dir(), "ide", "tpls", self.ide) tpls_dir = os.path.join(fs.get_source_dir(), "ide", "tpls", self.ide)
for root, _, files in os.walk(tpls_dir): for root, _, files in os.walk(tpls_dir):
for f in files: for f in files:
if not f.endswith(".tpl"): if not f.endswith(".tpl"):
@ -133,7 +117,7 @@ class ProjectGenerator(object):
_relpath = root.replace(tpls_dir, "") _relpath = root.replace(tpls_dir, "")
if _relpath.startswith(os.sep): if _relpath.startswith(os.sep):
_relpath = _relpath[1:] _relpath = _relpath[1:]
tpls.append((_relpath, join(root, f))) tpls.append((_relpath, os.path.join(root, f)))
return tpls return tpls
def generate(self): def generate(self):
@ -141,12 +125,12 @@ class ProjectGenerator(object):
for tpl_relpath, tpl_path in self.get_tpls(): for tpl_relpath, tpl_path in self.get_tpls():
dst_dir = self.project_dir dst_dir = self.project_dir
if tpl_relpath: if tpl_relpath:
dst_dir = join(self.project_dir, tpl_relpath) dst_dir = os.path.join(self.project_dir, tpl_relpath)
if not isdir(dst_dir): if not os.path.isdir(dst_dir):
os.makedirs(dst_dir) os.makedirs(dst_dir)
file_name = basename(tpl_path)[:-4] file_name = os.path.basename(tpl_path)[:-4]
contents = self._render_tpl(tpl_path, tpl_vars) contents = self._render_tpl(tpl_path, tpl_vars)
self._merge_contents(join(dst_dir, file_name), contents) self._merge_contents(os.path.join(dst_dir, file_name), contents)
@staticmethod @staticmethod
def _render_tpl(tpl_path, tpl_vars): def _render_tpl(tpl_path, tpl_vars):
@ -155,7 +139,7 @@ class ProjectGenerator(object):
@staticmethod @staticmethod
def _merge_contents(dst_path, contents): def _merge_contents(dst_path, contents):
if basename(dst_path) == ".gitignore" and isfile(dst_path): if os.path.basename(dst_path) == ".gitignore" and os.path.isfile(dst_path):
return return
with codecs.open(dst_path, "w", encoding="utf8") as fp: with codecs.open(dst_path, "w", encoding="utf8") as fp:
fp.write(contents) fp.write(contents)

View File

@ -62,29 +62,50 @@ def test_init_ide_without_board(clirunner, tmpdir):
assert isinstance(result.exception, ProjectEnvsNotAvailableError) assert isinstance(result.exception, ProjectEnvsNotAvailableError)
def test_init_ide_atom(clirunner, validate_cliresult, tmpdir): def test_init_ide_vscode(clirunner, validate_cliresult, tmpdir):
with tmpdir.as_cwd(): with tmpdir.as_cwd():
result = clirunner.invoke( result = clirunner.invoke(
cmd_init, ["--ide", "atom", "-b", "uno", "-b", "teensy31"] cmd_init, ["--ide", "vscode", "-b", "uno", "-b", "teensy31"]
) )
validate_cliresult(result) validate_cliresult(result)
validate_pioproject(str(tmpdir)) validate_pioproject(str(tmpdir))
assert all( assert all(
[tmpdir.join(f).check() for f in (".clang_complete", ".gcc-flags.json")] [
tmpdir.join(".vscode").join(f).check()
for f in ("c_cpp_properties.json", "launch.json")
]
)
assert (
"framework-arduino-avr"
in tmpdir.join(".vscode").join("c_cpp_properties.json").read()
) )
assert "framework-arduino" in tmpdir.join(".clang_complete").read()
# switch to NodeMCU # switch to NodeMCU
result = clirunner.invoke(cmd_init, ["--ide", "atom", "-b", "nodemcuv2"]) result = clirunner.invoke(cmd_init, ["--ide", "vscode", "-b", "nodemcuv2"])
validate_cliresult(result) validate_cliresult(result)
validate_pioproject(str(tmpdir)) validate_pioproject(str(tmpdir))
assert "arduinoespressif" in tmpdir.join(".clang_complete").read() assert (
"framework-arduinoespressif8266"
in tmpdir.join(".vscode").join("c_cpp_properties.json").read()
)
# switch to teensy31 via env name
result = clirunner.invoke(cmd_init, ["--ide", "vscode", "-e", "teensy31"])
validate_cliresult(result)
validate_pioproject(str(tmpdir))
assert (
"framework-arduinoteensy"
in tmpdir.join(".vscode").join("c_cpp_properties.json").read()
)
# switch to the first board # switch to the first board
result = clirunner.invoke(cmd_init, ["--ide", "atom"]) result = clirunner.invoke(cmd_init, ["--ide", "vscode"])
validate_cliresult(result) validate_cliresult(result)
validate_pioproject(str(tmpdir)) validate_pioproject(str(tmpdir))
assert "framework-arduino" in tmpdir.join(".clang_complete").read() assert (
"framework-arduino-avr"
in tmpdir.join(".vscode").join("c_cpp_properties.json").read()
)
def test_init_ide_eclipse(clirunner, validate_cliresult): def test_init_ide_eclipse(clirunner, validate_cliresult):