west: runners: Guess build folder

When using a build folder format with build.dir-fmt that includes any
parameters that need resolving, the west runners cannot find the folder
since the required information (board, source dir or app) is not
available.
Add a very simple heuristic to support the case where a build folder
starts with a hardcoded prefix (for example 'build/') and a single build
is present under that prefix.
The heuristic is gated behind a new configuration option:
build.guess-dir

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2019-06-17 11:47:11 +02:00 committed by Anas Nashif
parent 2192f1d0a4
commit 41f1f648f6
3 changed files with 49 additions and 10 deletions

View file

@ -219,6 +219,16 @@ You can :ref:`configure <west-config-cmd>` ``west build`` using these options.
- String, default ``Ninja``. The `CMake Generator`_ to use to create a
build system. (To set a generator for a single build, see the
:ref:`above example <west-building-generator>`)
* - ``build.guess-dir``
- String, instructs west whether to try to guess what build folder to use
when ``build.dir-fmt`` is in use and not enough information is available
to resolve the build folder name. Can take these values:
- ``never`` (default): Never try to guess, bail out instead and
require the user to provide a build folder with ``-d``.
- ``runners``: Try to guess the folder when using any of the 'runner'
commands. These are typically all commands that invoke an external
tool, such as ``flash`` and ``debug``.
* - ``build.pristine``
- String. Controls the way in which ``west build`` may clean the build
folder before building. Can take the following values:

View file

@ -12,6 +12,7 @@ See build.py for the build command itself.
import zcmake
import os
from pathlib import Path
from west import log
from west.configuration import config
from west.util import escapes_directory
@ -28,7 +29,7 @@ build.dir-fmt configuration variable is set) and the current directory are
checked, in that order. If one is a Zephyr build directory, it is used.
'''.format(DEFAULT_BUILD_DIR)
def _resolve_build_dir(fmt, cwd, **kwargs):
def _resolve_build_dir(fmt, guess, cwd, **kwargs):
# Remove any None values, we do not want 'None' as a string
kwargs = {k: v for k, v in kwargs.items() if v is not None}
# Check if source_dir is below cwd first
@ -40,9 +41,38 @@ def _resolve_build_dir(fmt, cwd, **kwargs):
# no meaningful relative path possible
kwargs['source_dir'] = ''
return fmt.format(**kwargs)
try:
return fmt.format(**kwargs)
except KeyError:
if not guess:
return None
def find_build_dir(dir, **kwargs):
# Guess the build folder by iterating through all sub-folders from the
# root of the format string and trying to resolve. If resolving fails,
# proceed to iterate over subfolders only if there is a single folder
# present on each iteration.
parts = Path(fmt).parts
b = Path('.')
for p in parts:
# default to cwd in the first iteration
curr = b
b = b.joinpath(p)
try:
# if fmt is an absolute path, the first iteration will always
# resolve '/'
b = Path(str(b).format(**kwargs))
except KeyError:
# Missing key, check sub-folders and match if a single one exists
while True:
dirs = [f for f in curr.iterdir() if f.is_dir()]
if len(dirs) != 1:
return None
curr = dirs[0]
if is_zephyr_build(str(curr)):
return str(curr)
return str(b)
def find_build_dir(dir, guess=False, **kwargs):
'''Heuristic for finding a build directory.
The default build directory is computed by reading the build.dir-fmt
@ -60,12 +90,8 @@ def find_build_dir(dir, **kwargs):
else:
cwd = os.getcwd()
default = config.get('build', 'dir-fmt', fallback=DEFAULT_BUILD_DIR)
try:
default = _resolve_build_dir(default, cwd, **kwargs)
log.dbg('config dir-fmt: {}'.format(default),
level=log.VERBOSE_EXTREME)
except KeyError:
default = None
default = _resolve_build_dir(default, guess, cwd, **kwargs)
log.dbg('config dir-fmt: {}'.format(default), level=log.VERBOSE_EXTREME)
if default and is_zephyr_build(default):
build_dir = default
elif is_zephyr_build(cwd):

View file

@ -19,6 +19,7 @@ from west import util
from build_helpers import find_build_dir, is_zephyr_build, \
FIND_BUILD_DIR_DESCRIPTION
from west.commands import CommandError
from west.configuration import config
from runners import get_runner_cls, ZephyrBinaryRunner, MissingProgram
@ -170,7 +171,9 @@ def _build_dir(args, die_if_none=True):
if args.build_dir:
return args.build_dir
dir = find_build_dir(None)
guess = config.get('build', 'guess-dir', fallback='never')
guess = True if guess == 'runners' else False
dir = find_build_dir(None, guess)
if dir and is_zephyr_build(dir):
return dir