forked from platformio/platformio-core
PlatformIO as Continuous Integration tool for embedded projects // Resolve #108
This commit is contained in:
@ -4,9 +4,11 @@ Release History
|
|||||||
2.0.0 (2015-??-??)
|
2.0.0 (2015-??-??)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
* Implemented PlatformIO CLI 2.0: "platform" related commands have been
|
* PlatformIO CLI 2.0: "platform" related commands have been
|
||||||
moved to ``platformio platforms`` subcommand
|
moved to ``platformio platforms`` subcommand
|
||||||
(`issue #158 <https://github.com/platformio/platformio/issues/158>`_)
|
(`issue #158 <https://github.com/platformio/platformio/issues/158>`_)
|
||||||
|
* PlatformIO as Continuous Integration (CI) tool for embedded projects
|
||||||
|
(`issue #108 <https://github.com/platformio/platformio/issues/108>`_)
|
||||||
* Created `PlatformIO gitter.im <https://gitter.im/platformio/platformio>`_ room
|
* Created `PlatformIO gitter.im <https://gitter.im/platformio/platformio>`_ room
|
||||||
(`issue #174 <https://github.com/platformio/platformio/issues/174>`_)
|
(`issue #174 <https://github.com/platformio/platformio/issues/174>`_)
|
||||||
* Added global ``-f, --force`` option which will force to accept any
|
* Added global ``-f, --force`` option which will force to accept any
|
||||||
|
125
docs/userguide/cmd_ci.rst
Normal file
125
docs/userguide/cmd_ci.rst
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
.. _cmd_ci:
|
||||||
|
|
||||||
|
platformio ci
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
platformio ci [OPTIONS] [SRC]
|
||||||
|
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
|
`Continuous integration (CI, wiki) <http://en.wikipedia.org/wiki/Continuous_integration>`_
|
||||||
|
is the practice, in software engineering, of merging all developer working
|
||||||
|
copies with a shared mainline several times a day.
|
||||||
|
|
||||||
|
:ref:`cmd_ci` command is conceived of as "hot key" for building project with
|
||||||
|
arbitrary source code structure. In a nutshell, using ``SRC`` and
|
||||||
|
:option:`platformio ci --lib` contents PlatformIO initialises via
|
||||||
|
:ref:`cmd_init` new project in :option:`platformio ci --build-dir`
|
||||||
|
with the build environments (using :option:`platformio ci --board` or
|
||||||
|
:option:`platformio ci --project-conf`) and processes them via :ref:`cmd_run`
|
||||||
|
command.
|
||||||
|
|
||||||
|
:ref:`cmd_ci` command is intended to be used in combination with the build
|
||||||
|
servers and the popular
|
||||||
|
`Continuous Integration Software <http://en.wikipedia.org/wiki/Comparison_of_continuous_integration_software>`_.
|
||||||
|
|
||||||
|
By integrating regularly, you can detect errors quickly, and locate them more
|
||||||
|
easily.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
:ref:`cmd_ci` command accepts **multiple** ``SRC`` arguments,
|
||||||
|
:option:`platformio ci --lib` and :option:`platformio ci --exclude` options
|
||||||
|
which can be a path to directory, file or
|
||||||
|
`Glob Pattern <http://en.wikipedia.org/wiki/Glob_(programming)>`_.
|
||||||
|
|
||||||
|
Options
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. program:: platformio ci
|
||||||
|
|
||||||
|
.. option::
|
||||||
|
-l, --lib
|
||||||
|
|
||||||
|
Source code which will be copied to ``%build_dir%/lib`` directly.
|
||||||
|
|
||||||
|
If :option:`platformio ci --lib` is a path to file (not to directory), then
|
||||||
|
PlatformIO will create temporary directory within ``%build_dir%/lib`` and copy
|
||||||
|
the rest files into it.
|
||||||
|
|
||||||
|
|
||||||
|
.. option::
|
||||||
|
--exclude
|
||||||
|
|
||||||
|
Exclude directories and/-or files from :option:`platformio ci --build-dir`. The
|
||||||
|
path must be relative to PlatformIO project within
|
||||||
|
:option:`platformio ci --build-dir`.
|
||||||
|
|
||||||
|
For example, exclude from project ``src`` directory:
|
||||||
|
|
||||||
|
* ``examples`` folder
|
||||||
|
* ``*.h`` files from ``foo`` folder
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
platformio ci --exclude=src/examples --exclude=src/foo/*.h [SRC]
|
||||||
|
|
||||||
|
.. option::
|
||||||
|
--board, -b
|
||||||
|
|
||||||
|
Build project with automatically pre-generated environments based on board
|
||||||
|
settings.
|
||||||
|
|
||||||
|
For more details please look into :option:`platformio init --board`.
|
||||||
|
|
||||||
|
.. option::
|
||||||
|
--build-dir
|
||||||
|
|
||||||
|
Path to directory where PlatformIO will initialise new project. By default it's
|
||||||
|
temporary directory within your operation system.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This directory will be removed at the end of build process. If you want to
|
||||||
|
keep it, please use :option:`platformio ci --keep-build-dir`.
|
||||||
|
|
||||||
|
.. option::
|
||||||
|
--keep-build-dir
|
||||||
|
|
||||||
|
Don't remove :option:`platformio ci --build-dir` after build process.
|
||||||
|
|
||||||
|
.. option::
|
||||||
|
--project-conf
|
||||||
|
|
||||||
|
Buid project using pre-configured :ref:`projectconf`.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
1. Integration `Travis.CI <http://travis-ci.org/>`_ for GitHub
|
||||||
|
`USB_Host_Shield_2.0 <https://github.com/felis/USB_Host_Shield_2.0>`_
|
||||||
|
project. The ``.travis.yml`` configuration file:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
language: python
|
||||||
|
python:
|
||||||
|
- "2.7"
|
||||||
|
|
||||||
|
env:
|
||||||
|
- PLATFORMIO_CI_SRC=examples/Bluetooth/PS3SPP/PS3SPP.ino
|
||||||
|
- PLATFORMIO_CI_SRC=examples/pl2303/pl2303_gps/pl2303_gps.ino
|
||||||
|
|
||||||
|
install:
|
||||||
|
- python -c "$(curl -fsSL https://raw.githubusercontent.com/platformio/platformio/master/scripts/get-platformio.py)"
|
||||||
|
|
||||||
|
script:
|
||||||
|
- platformio ci --lib="." --board=uno --board=teensy31 --board=due
|
@ -44,6 +44,7 @@ Commands
|
|||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
cmd_boards
|
cmd_boards
|
||||||
|
cmd_ci
|
||||||
cmd_init
|
cmd_init
|
||||||
platformio lib <lib/index>
|
platformio lib <lib/index>
|
||||||
platformio platforms <platforms/index>
|
platformio platforms <platforms/index>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Copyright (C) Ivan Kravets <me@ikravets.com>
|
# Copyright (C) Ivan Kravets <me@ikravets.com>
|
||||||
# See LICENSE for details.
|
# See LICENSE for details.
|
||||||
|
|
||||||
VERSION = (2, 0, "0.dev4")
|
VERSION = (2, 0, "0.dev5")
|
||||||
__version__ = ".".join([str(s) for s in VERSION])
|
__version__ = ".".join([str(s) for s in VERSION])
|
||||||
|
|
||||||
__title__ = "platformio"
|
__title__ = "platformio"
|
||||||
|
139
platformio/commands/ci.py
Normal file
139
platformio/commands/ci.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
# Copyright (C) Ivan Kravets <me@ikravets.com>
|
||||||
|
# See LICENSE for details.
|
||||||
|
|
||||||
|
from glob import glob
|
||||||
|
from os import environ, makedirs, remove
|
||||||
|
from os.path import basename, isdir, isfile, join
|
||||||
|
from shutil import copyfile, copytree, rmtree
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
|
||||||
|
import click
|
||||||
|
|
||||||
|
from platformio import app
|
||||||
|
from platformio.commands.init import cli as cmd_init
|
||||||
|
from platformio.commands.run import cli as cmd_run
|
||||||
|
from platformio.exception import CIBuildEnvsEmpty
|
||||||
|
from platformio.util import get_boards
|
||||||
|
|
||||||
|
|
||||||
|
def validate_path(ctx, param, value): # pylint: disable=W0613
|
||||||
|
invalid_path = None
|
||||||
|
for p in value:
|
||||||
|
if not glob(p):
|
||||||
|
invalid_path = p
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
assert invalid_path is None
|
||||||
|
return value
|
||||||
|
except AssertionError:
|
||||||
|
raise click.BadParameter("Found invalid path: %s" % invalid_path)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_boards(ctx, param, value): # pylint: disable=W0613
|
||||||
|
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))
|
||||||
|
|
||||||
|
|
||||||
|
@click.command("ci", short_help="Continuous Integration")
|
||||||
|
@click.argument("src", nargs=-1, callback=validate_path)
|
||||||
|
@click.option("--lib", "-l", multiple=True, callback=validate_path)
|
||||||
|
@click.option("--exclude", multiple=True)
|
||||||
|
@click.option("--board", "-b", multiple=True, callback=validate_boards)
|
||||||
|
@click.option("--build-dir", default=mkdtemp,
|
||||||
|
type=click.Path(exists=True, file_okay=False, dir_okay=True,
|
||||||
|
writable=True, resolve_path=True))
|
||||||
|
@click.option("--keep-build-dir", is_flag=True)
|
||||||
|
@click.option("--project-conf",
|
||||||
|
type=click.Path(exists=True, file_okay=True, dir_okay=False,
|
||||||
|
readable=True, resolve_path=True))
|
||||||
|
@click.pass_context
|
||||||
|
def cli(ctx, src, lib, exclude, board, # pylint: disable=R0913
|
||||||
|
build_dir, keep_build_dir, project_conf):
|
||||||
|
|
||||||
|
if not src:
|
||||||
|
src = environ.get("PLATFORMIO_CI_SRC", "").split(":")
|
||||||
|
if not src:
|
||||||
|
raise click.BadParameter("Missing argument 'src'")
|
||||||
|
|
||||||
|
try:
|
||||||
|
app.set_session_var("force_option", True)
|
||||||
|
_clean_dir(build_dir)
|
||||||
|
|
||||||
|
for dir_name, patterns in dict(lib=lib, src=src).iteritems():
|
||||||
|
if not patterns:
|
||||||
|
continue
|
||||||
|
contents = []
|
||||||
|
for p in patterns:
|
||||||
|
contents += glob(p)
|
||||||
|
_copy_contents(join(build_dir, dir_name), contents)
|
||||||
|
|
||||||
|
if project_conf and isfile(project_conf):
|
||||||
|
copyfile(project_conf, join(build_dir, "platformio.ini"))
|
||||||
|
elif not board:
|
||||||
|
raise CIBuildEnvsEmpty()
|
||||||
|
|
||||||
|
if exclude:
|
||||||
|
_exclude_contents(build_dir, exclude)
|
||||||
|
|
||||||
|
# initialise project
|
||||||
|
ctx.invoke(cmd_init, project_dir=build_dir, board=board,
|
||||||
|
disable_auto_uploading=True)
|
||||||
|
|
||||||
|
# process project
|
||||||
|
ctx.invoke(cmd_run, project_dir=build_dir)
|
||||||
|
finally:
|
||||||
|
if not keep_build_dir:
|
||||||
|
rmtree(build_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def _clean_dir(dirpath):
|
||||||
|
rmtree(dirpath)
|
||||||
|
makedirs(dirpath)
|
||||||
|
|
||||||
|
|
||||||
|
def _copy_contents(dst_dir, contents):
|
||||||
|
items = {
|
||||||
|
"dirs": set(),
|
||||||
|
"files": set()
|
||||||
|
}
|
||||||
|
|
||||||
|
for path in contents:
|
||||||
|
if isdir(path):
|
||||||
|
items['dirs'].add(path)
|
||||||
|
elif isfile(path):
|
||||||
|
items['files'].add(path)
|
||||||
|
|
||||||
|
dst_dir_name = basename(dst_dir)
|
||||||
|
|
||||||
|
if dst_dir_name == "src" and len(items['dirs']) == 1:
|
||||||
|
copytree(list(items['dirs']).pop(), dst_dir)
|
||||||
|
else:
|
||||||
|
makedirs(dst_dir)
|
||||||
|
for d in items['dirs']:
|
||||||
|
copytree(d, join(dst_dir, basename(d)))
|
||||||
|
|
||||||
|
if not items['files']:
|
||||||
|
return
|
||||||
|
|
||||||
|
if dst_dir_name == "lib":
|
||||||
|
dst_dir = join(dst_dir, mkdtemp(dir=dst_dir))
|
||||||
|
|
||||||
|
for f in items['files']:
|
||||||
|
copyfile(f, join(dst_dir, basename(f)))
|
||||||
|
|
||||||
|
|
||||||
|
def _exclude_contents(dst_dir, patterns):
|
||||||
|
contents = []
|
||||||
|
for p in patterns:
|
||||||
|
contents += glob(join(dst_dir, p))
|
||||||
|
for path in contents:
|
||||||
|
if isdir(path):
|
||||||
|
rmtree(path)
|
||||||
|
elif isfile(path):
|
||||||
|
remove(path)
|
@ -165,6 +165,15 @@ class UpgraderFailed(PlatformioException):
|
|||||||
MESSAGE = "An error occurred while upgrading PlatformIO"
|
MESSAGE = "An error occurred while upgrading PlatformIO"
|
||||||
|
|
||||||
|
|
||||||
|
class CIBuildEnvsEmpty(PlatformioException):
|
||||||
|
|
||||||
|
MESSAGE = (
|
||||||
|
"Can't find PlatformIO build environments.\nPlease specify `--board` "
|
||||||
|
"or path to `platformio.ini` with predefined environments using "
|
||||||
|
"`--project-conf` option"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SConsNotInstalled(PlatformioException):
|
class SConsNotInstalled(PlatformioException):
|
||||||
|
|
||||||
MESSAGE = (
|
MESSAGE = (
|
||||||
|
Reference in New Issue
Block a user