2016-01-01 20:51:48 +02:00
|
|
|
# Copyright 2014-2016 Ivan Kravets <me@ikravets.com>
|
2015-11-18 17:16:17 +02:00
|
|
|
#
|
|
|
|
# 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.
|
2014-06-12 21:17:45 +03:00
|
|
|
|
2014-11-30 18:14:18 +02:00
|
|
|
from os import getcwd, makedirs
|
2014-06-12 21:17:45 +03:00
|
|
|
from os.path import isdir, isfile, join
|
|
|
|
from shutil import copyfile
|
|
|
|
|
2014-11-30 18:14:18 +02:00
|
|
|
import click
|
2014-06-12 21:17:45 +03:00
|
|
|
|
2016-03-07 17:42:15 +02:00
|
|
|
from platformio import app, exception, util
|
2015-09-06 18:16:09 +03:00
|
|
|
from platformio.commands.platforms import \
|
|
|
|
platforms_install as cli_platforms_install
|
2015-04-24 14:43:13 +01:00
|
|
|
from platformio.ide.projectgenerator import ProjectGenerator
|
2015-09-06 18:16:09 +03:00
|
|
|
from platformio.platforms.base import PlatformFactory
|
2014-12-29 20:22:01 +02:00
|
|
|
from platformio.util import get_boards, get_source_dir
|
2014-06-12 21:17:45 +03:00
|
|
|
|
|
|
|
|
2015-04-22 14:58:42 +01:00
|
|
|
def validate_boards(ctx, param, value): # pylint: disable=W0613
|
2015-04-20 19:55:18 +01:00
|
|
|
unknown_boards = set(value) - set(get_boards().keys())
|
|
|
|
try:
|
|
|
|
assert not unknown_boards
|
|
|
|
return value
|
|
|
|
except AssertionError:
|
|
|
|
raise click.BadParameter(
|
|
|
|
"%s. Please search for the board types using "
|
|
|
|
"`platformio boards` command" % ", ".join(unknown_boards))
|
|
|
|
|
|
|
|
|
2014-11-30 18:14:18 +02:00
|
|
|
@click.command("init", short_help="Initialize new PlatformIO based project")
|
2015-02-19 17:20:08 +02:00
|
|
|
@click.option("--project-dir", "-d", default=getcwd,
|
2014-11-30 18:14:18 +02:00
|
|
|
type=click.Path(exists=True, file_okay=False, dir_okay=True,
|
|
|
|
writable=True, resolve_path=True))
|
2015-04-20 19:55:18 +01:00
|
|
|
@click.option("--board", "-b", multiple=True, metavar="TYPE",
|
|
|
|
callback=validate_boards)
|
2015-04-24 14:43:13 +01:00
|
|
|
@click.option("--ide",
|
|
|
|
type=click.Choice(ProjectGenerator.get_supported_ides()))
|
2015-12-03 17:19:43 +02:00
|
|
|
@click.option("--enable-auto-uploading", is_flag=True)
|
2015-05-06 11:28:56 +01:00
|
|
|
@click.option("--env-prefix", default="")
|
2015-09-06 18:16:09 +03:00
|
|
|
@click.pass_context
|
|
|
|
def cli(ctx, project_dir, board, ide, # pylint: disable=R0913
|
2015-12-03 17:19:43 +02:00
|
|
|
enable_auto_uploading, env_prefix):
|
2015-01-31 22:42:52 +02:00
|
|
|
|
2014-11-30 18:14:18 +02:00
|
|
|
if project_dir == getcwd():
|
2015-01-31 22:42:52 +02:00
|
|
|
click.secho("\nThe current working directory", fg="yellow", nl=False)
|
2014-12-10 21:40:39 +02:00
|
|
|
click.secho(" %s " % project_dir, fg="cyan", nl=False)
|
2014-11-30 18:14:18 +02:00
|
|
|
click.secho(
|
2015-04-23 12:40:19 +01:00
|
|
|
"will be used for project.\n"
|
2014-11-30 18:14:18 +02:00
|
|
|
"You can specify another project directory via\n"
|
2015-04-20 19:55:18 +01:00
|
|
|
"`platformio init -d %PATH_TO_THE_PROJECT_DIR%` command.",
|
2014-11-30 18:14:18 +02:00
|
|
|
fg="yellow"
|
|
|
|
)
|
2015-04-20 19:55:18 +01:00
|
|
|
click.echo("")
|
2014-11-30 18:14:18 +02:00
|
|
|
|
|
|
|
click.echo("The next files/directories will be created in %s" %
|
2014-12-10 21:40:39 +02:00
|
|
|
click.style(project_dir, fg="cyan"))
|
2015-01-31 22:42:52 +02:00
|
|
|
click.echo("%s - Project Configuration File. |-> PLEASE EDIT ME <-|" %
|
2014-11-30 18:14:18 +02:00
|
|
|
click.style("platformio.ini", fg="cyan"))
|
2015-10-13 14:01:16 +01:00
|
|
|
click.echo("%s - Put your source files here" %
|
2014-11-30 18:14:18 +02:00
|
|
|
click.style("src", fg="cyan"))
|
2015-08-21 23:56:22 +03:00
|
|
|
click.echo("%s - Put here project specific (private) libraries" %
|
2014-11-30 18:14:18 +02:00
|
|
|
click.style("lib", fg="cyan"))
|
|
|
|
|
2015-04-23 12:40:19 +01:00
|
|
|
if (app.get_setting("enable_prompts") and
|
|
|
|
not click.confirm("Do you want to continue?")):
|
2015-02-15 23:39:02 +02:00
|
|
|
raise exception.AbortedByUser()
|
2014-12-29 20:22:01 +02:00
|
|
|
|
2016-03-07 17:42:15 +02:00
|
|
|
init_base_project(project_dir)
|
2015-04-23 12:40:19 +01:00
|
|
|
|
|
|
|
if board:
|
2015-04-23 12:54:59 +01:00
|
|
|
fill_project_envs(
|
2016-03-07 17:42:15 +02:00
|
|
|
ctx, join(project_dir, "platformio.ini"), board,
|
|
|
|
enable_auto_uploading, env_prefix, ide is not None
|
2015-12-08 18:42:50 +02:00
|
|
|
)
|
2015-04-23 12:40:19 +01:00
|
|
|
|
2015-04-24 14:43:13 +01:00
|
|
|
if ide:
|
2015-12-08 18:42:50 +02:00
|
|
|
if not board:
|
|
|
|
raise exception.BoardNotDefined()
|
|
|
|
if len(board) > 1:
|
|
|
|
click.secho(
|
|
|
|
"Warning! You have initialised project with more than 1 board"
|
|
|
|
" for the specified IDE.\n"
|
|
|
|
"However, the IDE features (code autocompletion, syntax lint)"
|
|
|
|
" have been configured for the first board '%s' from your list"
|
|
|
|
" '%s'." % (board[0], ", ".join(board)),
|
|
|
|
fg="yellow"
|
|
|
|
)
|
|
|
|
pg = ProjectGenerator(
|
|
|
|
project_dir, ide, board[0])
|
2015-04-24 14:43:13 +01:00
|
|
|
pg.generate()
|
|
|
|
|
2015-04-23 12:40:19 +01:00
|
|
|
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 "
|
2015-12-03 17:19:43 +02:00
|
|
|
"files)\n"
|
|
|
|
"`platformio run --help` - additional information",
|
2015-04-23 12:40:19 +01:00
|
|
|
fg="green"
|
|
|
|
)
|
|
|
|
|
2014-12-29 20:22:01 +02:00
|
|
|
|
2016-03-07 17:42:15 +02:00
|
|
|
def init_base_project(project_dir):
|
|
|
|
platformio_ini = join(project_dir, "platformio.ini")
|
|
|
|
if not isfile(platformio_ini):
|
|
|
|
copyfile(join(get_source_dir(), "projectconftpl.ini"),
|
|
|
|
platformio_ini)
|
2015-04-23 12:54:59 +01:00
|
|
|
|
2016-03-07 17:42:15 +02:00
|
|
|
lib_dir = join(project_dir, "lib")
|
|
|
|
src_dir = join(project_dir, "src")
|
|
|
|
with util.cd(project_dir):
|
|
|
|
config = util.get_project_config()
|
|
|
|
if config.has_option("platformio", "src_dir"):
|
|
|
|
src_dir = join(project_dir, config.get("platformio", "src_dir"))
|
2015-09-06 18:16:09 +03:00
|
|
|
|
2016-03-07 17:42:15 +02:00
|
|
|
for d in (src_dir, lib_dir):
|
|
|
|
if not isdir(d):
|
|
|
|
makedirs(d)
|
2015-09-06 18:16:09 +03:00
|
|
|
|
2016-03-07 17:42:15 +02:00
|
|
|
init_lib_readme(lib_dir)
|
|
|
|
init_ci_conf(project_dir)
|
|
|
|
init_cvs_ignore(project_dir)
|
2015-12-04 15:18:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
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("""
|
|
|
|
This directory is intended for the project specific (private) libraries.
|
|
|
|
PlatformIO will compile them to static libraries and link to executable file.
|
|
|
|
|
|
|
|
The source code of each library should be placed in separate directory, like
|
|
|
|
"lib/private_lib/[here are source files]".
|
|
|
|
|
2016-01-15 23:37:41 +02:00
|
|
|
For example, see how can be organized `Foo` and `Bar` libraries:
|
2015-12-04 15:18:31 +02:00
|
|
|
|
|
|
|
|--lib
|
|
|
|
| |--Bar
|
|
|
|
| | |--docs
|
|
|
|
| | |--examples
|
|
|
|
| | |--src
|
|
|
|
| | |- Bar.c
|
|
|
|
| | |- Bar.h
|
|
|
|
| |--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.
|
|
|
|
|
|
|
|
See additional options for PlatformIO Library Dependency Finder `lib_*`:
|
|
|
|
|
|
|
|
http://docs.platformio.org/en/latest/projectconf.html#lib-install
|
|
|
|
|
|
|
|
""")
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
# several times a day < http://docs.platformio.org/en/latest/ci/index.html >
|
|
|
|
#
|
|
|
|
# Documentation:
|
|
|
|
#
|
|
|
|
# * Travis CI Embedded Builds with PlatformIO
|
|
|
|
# < https://docs.travis-ci.com/user/integration/platformio/ >
|
|
|
|
#
|
|
|
|
# * PlatformIO integration with Travis CI
|
|
|
|
# < http://docs.platformio.org/en/latest/ci/travis.html >
|
|
|
|
#
|
|
|
|
# * User Guide for `platformio ci` command
|
|
|
|
# < http://docs.platformio.org/en/latest/userguide/cmd_ci.html >
|
|
|
|
#
|
2015-12-07 22:23:20 +02:00
|
|
|
#
|
|
|
|
# Please choice one of the following templates (proposed below) and uncomment
|
|
|
|
# it (remove "# " before each line) or use own configuration according to the
|
|
|
|
# Travis CI documentation (see above).
|
|
|
|
#
|
2015-12-04 15:18:31 +02:00
|
|
|
|
|
|
|
|
2015-12-07 22:23:20 +02:00
|
|
|
#
|
|
|
|
# Template #1: General project. Test it using existing `platformio.ini`.
|
|
|
|
#
|
|
|
|
|
|
|
|
# language: python
|
|
|
|
# python:
|
|
|
|
# - "2.7"
|
|
|
|
#
|
|
|
|
# sudo: false
|
|
|
|
# cache:
|
|
|
|
# directories:
|
|
|
|
# - "~/.platformio"
|
|
|
|
#
|
|
|
|
# install:
|
|
|
|
# - pip install -U platformio
|
|
|
|
#
|
|
|
|
# script:
|
|
|
|
# - platformio run
|
2015-12-04 15:18:31 +02:00
|
|
|
|
|
|
|
|
2015-12-07 22:23:20 +02:00
|
|
|
#
|
|
|
|
# Template #2: The project is intended to by used as a library with examples
|
|
|
|
#
|
|
|
|
|
|
|
|
# language: python
|
|
|
|
# python:
|
|
|
|
# - "2.7"
|
|
|
|
#
|
|
|
|
# sudo: false
|
|
|
|
# cache:
|
|
|
|
# directories:
|
|
|
|
# - "~/.platformio"
|
|
|
|
#
|
|
|
|
# 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
|
|
|
|
#
|
|
|
|
# script:
|
|
|
|
# - platformio ci --lib="." --board=TYPE_1 --board=TYPE_2 --board=TYPE_N
|
2015-12-04 15:18:31 +02:00
|
|
|
""")
|
2015-12-05 23:34:25 +02:00
|
|
|
|
|
|
|
|
|
|
|
def init_cvs_ignore(project_dir):
|
|
|
|
if isfile(join(project_dir, ".gitignore")):
|
|
|
|
return
|
|
|
|
with open(join(project_dir, ".gitignore"), "w") as f:
|
2015-12-11 14:23:12 +02:00
|
|
|
f.write(".pioenvs")
|
2016-03-07 17:42:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
def fill_project_envs( # pylint: disable=too-many-arguments,too-many-locals
|
|
|
|
ctx, platformio_ini, board_types, enable_auto_uploading,
|
|
|
|
env_prefix, force_download):
|
|
|
|
builtin_boards = get_boards()
|
|
|
|
content = []
|
|
|
|
used_envs = []
|
|
|
|
used_platforms = []
|
|
|
|
|
|
|
|
with open(platformio_ini) as f:
|
|
|
|
used_envs = [l.strip() for l in f.read().splitlines() if
|
|
|
|
l.strip().startswith("[env:")]
|
|
|
|
|
|
|
|
for type_ in board_types:
|
|
|
|
data = builtin_boards[type_]
|
|
|
|
used_platforms.append(data['platform'])
|
|
|
|
env_name = "[env:%s%s]" % (env_prefix, type_)
|
|
|
|
|
|
|
|
if env_name in used_envs:
|
|
|
|
continue
|
|
|
|
|
|
|
|
content.append("")
|
|
|
|
content.append(env_name)
|
|
|
|
content.append("platform = %s" % data['platform'])
|
|
|
|
|
|
|
|
# find default framework for board
|
|
|
|
frameworks = data.get("frameworks")
|
|
|
|
if frameworks:
|
|
|
|
content.append("framework = %s" % frameworks[0])
|
|
|
|
|
|
|
|
content.append("board = %s" % type_)
|
|
|
|
if enable_auto_uploading:
|
|
|
|
content.append("targets = upload")
|
|
|
|
|
|
|
|
if force_download and used_platforms:
|
|
|
|
_install_dependent_platforms(ctx, used_platforms)
|
|
|
|
|
|
|
|
if not content:
|
|
|
|
return
|
|
|
|
|
|
|
|
with open(platformio_ini, "a") as f:
|
|
|
|
content.append("")
|
|
|
|
f.write("\n".join(content))
|
|
|
|
|
|
|
|
|
|
|
|
def _install_dependent_platforms(ctx, platforms):
|
|
|
|
installed_platforms = PlatformFactory.get_platforms(installed=True).keys()
|
|
|
|
if set(platforms) <= set(installed_platforms):
|
|
|
|
return
|
|
|
|
ctx.invoke(
|
|
|
|
cli_platforms_install,
|
|
|
|
platforms=list(set(platforms) - set(installed_platforms))
|
|
|
|
)
|