Files
platformio-core/platformio/commands/init.py

356 lines
10 KiB
Python
Raw Normal View History

# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
2016-09-13 20:39:04 +03:00
# pylint: disable=too-many-arguments,too-many-locals, too-many-branches
2014-11-30 18:14:18 +02:00
from os import getcwd, makedirs
from os.path import isdir, isfile, join
from shutil import copyfile
2014-11-30 18:14:18 +02:00
import click
2016-08-09 15:24:56 +03:00
from platformio import exception, util
from platformio.commands.platform import \
platform_install as cli_platform_install
from platformio.ide.projectgenerator import ProjectGenerator
from platformio.managers.platform import PlatformManager
2015-04-22 14:58:42 +01:00
def validate_boards(ctx, param, value): # pylint: disable=W0613
pm = PlatformManager()
for id_ in value:
try:
pm.board_config(id_)
except exception.UnknownBoard:
raise click.BadParameter(
"`%s`. Please search for board ID using `platformio boards` "
"command" % id_)
return value
@click.command(
"init", short_help="Initialize PlatformIO project or update existing")
2016-08-03 23:38:20 +03:00
@click.option(
"--project-dir",
"-d",
default=getcwd,
type=click.Path(
exists=True,
file_okay=False,
dir_okay=True,
writable=True,
resolve_path=True))
@click.option(
"-b", "--board", multiple=True, metavar="ID", callback=validate_boards)
@click.option(
"--ide", type=click.Choice(ProjectGenerator.get_supported_ides()))
@click.option("-O", "--project-option", multiple=True)
@click.option("--env-prefix", default="")
@click.option("-s", "--silent", is_flag=True)
@click.pass_context
2016-10-31 20:05:34 +02:00
def cli(
ctx, # pylint: disable=R0913
2016-08-03 23:38:20 +03:00
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(
2018-08-30 19:22:36 +02:00
"will be used for the project.\n"
"You can specify another project directory via\n"
"`platformio init -d %PATH_TO_THE_PROJECT_DIR%` command.",
fg="yellow")
click.echo("")
click.echo("The next files/directories have been created in %s" %
2017-03-02 17:09:22 +02:00
click.style(project_dir, fg="cyan"))
click.echo("%s - Project Configuration File" % click.style(
"platformio.ini", fg="cyan"))
2017-06-05 16:05:05 +03:00
click.echo(
"%s - Put your source files here" % click.style("src", fg="cyan"))
click.echo("%s - Put here project specific (private) libraries" %
2017-03-02 17:09:22 +02:00
click.style("lib", fg="cyan"))
2014-11-30 18:14:18 +02:00
init_base_project(project_dir)
if board:
fill_project_envs(ctx, project_dir, board, project_option, env_prefix,
ide is not None)
if ide:
env_name = get_best_envname(project_dir, board)
if not env_name:
2015-12-08 18:42:50 +02:00
raise exception.BoardNotDefined()
pg = ProjectGenerator(project_dir, ide, env_name)
pg.generate()
if not silent:
click.secho(
"\nProject has been successfully initialized!\nUseful commands:\n"
"`platformio run` - process/build project from the current "
"directory\n"
"`platformio run --target upload` or `platformio run -t upload` "
"- upload firmware to embedded board\n"
"`platformio run --target clean` - clean project (remove compiled "
"files)\n"
"`platformio run --help` - additional information",
fg="green")
def get_best_envname(project_dir, boards=None):
config = util.load_project_config(project_dir)
env_default = None
if config.has_option("platformio", "env_default"):
env_default = config.get("platformio",
"env_default").split(", ")[0].strip()
if env_default:
return env_default
section = None
for section in config.sections():
if not section.startswith("env:"):
continue
elif config.has_option(section, "board") and (not boards or config.get(
section, "board") in boards):
break
return section[4:] if section else None
def init_base_project(project_dir):
if not util.is_platformio_project(project_dir):
2016-08-03 23:38:20 +03:00
copyfile(
join(util.get_source_dir(), "projectconftpl.ini"),
join(project_dir, "platformio.ini"))
with util.cd(project_dir):
lib_dir = util.get_projectlib_dir()
src_dir = util.get_projectsrc_dir()
for d in (src_dir, lib_dir):
if not isdir(d):
makedirs(d)
init_lib_readme(lib_dir)
init_ci_conf(project_dir)
init_cvs_ignore(project_dir)
def init_lib_readme(lib_dir):
if isfile(join(lib_dir, "readme.txt")):
return
with open(join(lib_dir, "readme.txt"), "w") as f:
f.write("""
2018-08-30 19:22:36 +02:00
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link them to executable files.
2018-08-30 19:22:36 +02:00
The source code of each library should be placed in separate directories, like
"lib/private_lib/[here are source files]".
2018-08-30 19:22:36 +02:00
For example, see the structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
2018-08-15 19:44:02 +03:00
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- readme.txt --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
Then in `src/main.c` you should use:
#include <Foo.h>
#include <Bar.h>
// rest H/C/CPP code
PlatformIO will find your libraries automatically, configure preprocessor's
include paths and build them.
More information about PlatformIO Library Dependency Finder
2018-08-15 19:44:02 +03:00
- https://docs.platformio.org/page/librarymanager/ldf.html
""")
def init_ci_conf(project_dir):
if isfile(join(project_dir, ".travis.yml")):
return
with open(join(project_dir, ".travis.yml"), "w") as f:
f.write("""# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
2018-08-15 19:44:02 +03:00
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
2018-08-15 19:44:02 +03:00
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
2018-08-15 19:44:02 +03:00
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
2015-12-07 22:23:20 +02:00
#
2018-08-30 19:22:36 +02:00
# Please choose one of the following templates (proposed below) and uncomment
2015-12-07 22:23:20 +02:00
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
2015-12-07 22:23:20 +02:00
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
2018-02-20 14:29:20 +02:00
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
2015-12-07 22:23:20 +02:00
# install:
# - pip install -U platformio
2018-02-20 14:29:20 +02:00
# - platformio update
2015-12-07 22:23:20 +02:00
#
# script:
# - platformio run
2015-12-07 22:23:20 +02:00
#
2018-08-30 19:22:36 +02:00
# Template #2: The project is intended to be used as a library with examples.
2015-12-07 22:23:20 +02:00
#
# language: python
# python:
# - "2.7"
#
2018-02-20 14:29:20 +02:00
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
2015-12-07 22:23:20 +02:00
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
2018-02-20 14:29:20 +02:00
# - platformio update
2015-12-07 22:23:20 +02:00
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
""")
2015-12-05 23:34:25 +02:00
def init_cvs_ignore(project_dir):
ignore_path = join(project_dir, ".gitignore")
default = [".pioenvs\n", ".piolibdeps\n"]
current = []
modified = False
if isfile(ignore_path):
with open(ignore_path) as fp:
current = fp.readlines()
2016-08-29 13:35:35 +03:00
if current and not current[-1].endswith("\n"):
current[-1] += "\n"
for d in default:
if d not in current:
modified = True
current.append(d)
if not modified:
return
with open(ignore_path, "w") as fp:
fp.writelines(current)
2016-09-13 20:39:04 +03:00
def fill_project_envs(ctx, project_dir, board_ids, project_option, env_prefix,
force_download):
content = []
used_boards = []
used_platforms = []
config = util.load_project_config(project_dir)
for section in config.sections():
2016-10-31 20:05:34 +02:00
cond = [
2017-06-05 16:05:05 +03:00
section.startswith("env:"),
config.has_option(section, "board")
2016-10-31 20:05:34 +02:00
]
if all(cond):
used_boards.append(config.get(section, "board"))
pm = PlatformManager()
for id_ in board_ids:
board_config = pm.board_config(id_)
used_platforms.append(board_config['platform'])
if id_ in used_boards:
continue
2016-08-10 21:58:12 +03:00
used_boards.append(id_)
envopts = {"platform": board_config['platform'], "board": id_}
# find default framework for board
frameworks = board_config.get("frameworks")
if frameworks:
envopts['framework'] = frameworks[0]
for item in project_option:
if "=" not in item:
continue
_name, _value = item.split("=", 1)
envopts[_name.strip()] = _value.strip()
content.append("")
content.append("[env:%s%s]" % (env_prefix, id_))
for name, value in envopts.items():
content.append("%s = %s" % (name, value))
if force_download and used_platforms:
_install_dependent_platforms(ctx, used_platforms)
if not content:
return
with open(join(project_dir, "platformio.ini"), "a") as f:
content.append("")
f.write("\n".join(content))
def _install_dependent_platforms(ctx, platforms):
installed_platforms = [
2016-08-03 23:38:20 +03:00
p['name'] for p in PlatformManager().get_installed()
]
if set(platforms) <= set(installed_platforms):
return
ctx.invoke(
cli_platform_install,
2016-08-03 23:38:20 +03:00
platforms=list(set(platforms) - set(installed_platforms)))