Skip to content

Commit

Permalink
Merge pull request #33 from IRNAS/release/v0.5.0
Browse files Browse the repository at this point in the history
Release v0.5.0
  • Loading branch information
MarkoSagadin authored Dec 13, 2022
2 parents 3eb28b0 + 86aa209 commit beb55ae
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 95 deletions.
27 changes: 26 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## [Unreleased]

## [0.5.0] - 2022-12-13

### Added

- Command _east build_ will now after every build step copy
`compile_commands.json`, if found, from the build directory to the project
directory. This makes job of locating this file easier for clangd. Help
description for _east build_ was updated to reflect that.

### Changed

- Make east.yml optional for everything, except for the usage of east build
command with --build-type option.
- Make apps key and samples key inside east.yml optional. This is useful for
driver projects, which do not need apps, or any project that might not have
samples.

### Fixed

- Properly handle _east build_ commands outside of applications and samples.
This means that running _east build_ command will default to plain west
behaviour, as it should.

## [0.4.0] - 2022-11-21

### Added
Expand Down Expand Up @@ -71,7 +94,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Docker scripts for building and running docker containers, for development
purposes.

[Unreleased]: https://github.com/IRNAS/irnas-east-software/compare/v0.4.0...HEAD
[Unreleased]: https://github.com/IRNAS/irnas-east-software/compare/v0.5.0...HEAD

[0.5.0]: https://github.com/IRNAS/irnas-east-software/compare/v0.4.0...v0.5.0

[0.4.0]: https://github.com/IRNAS/irnas-east-software/compare/v0.3.0...v0.4.0

Expand Down
19 changes: 12 additions & 7 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,33 @@

The `east` tool provides a way to specify the project-specific configuration.
The configuration is done with an `east.yml` file, which needs to be placed in
the _root directory_ of the repo.
the _root directory_ of the repository.

Currently, the configuration is required for:

- specifying available build types for applications and samples available
through `--build-type` option which can be given to the `east build` command,
- specifying binary assets that will be created with the `east release` command.

This document describes the required fields of the `east.yml` file, how to use
_build-types_ and how to set up the project using the `east release` command.
`east.yml file` is optional; Users do not need to create to use `east`, however
it that case the above two mentioned functionalities will not work.

This document describes the expected contents of the `east.yml` file, what are
_build-types_, how to use them and how to specify binary assets for the
`east release` command.

## General structure of the configuration file

`east.yml` contains two main keys:

- `apps` - lists **one** or **more** applications with their own specific
configurations.
configurations. This key is optional (useful for driver projects).
- `samples` - lists **one** or **more** samples which can inherit configurations
from applications.
from applications. This key is optional (for projects that might not need
samples).

Below is an example file with comments that can be copied into a project and
modified:
Below is an example of `east.yml` with comments that can be copied into a
project and modified:

```yaml
apps:
Expand Down
3 changes: 1 addition & 2 deletions src/east/configuration-schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ type: map
mapping:
apps:
# app key is required, it needs to be a sequence
required: true
required: false
type: seq
sequence:
- type: map
Expand Down Expand Up @@ -57,4 +57,3 @@ mapping:
type: str
build-type:
type: str

87 changes: 55 additions & 32 deletions src/east/east_yml.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,6 @@ class EastYmlLoadError(RuntimeError):
"""Some error happened when trying to load east.yml."""


east_yml_load_error_msg = """
[bold yellow]east.yml[/] was [bold red]not found[/] in the project's root directory!
See documentation on how to create it.
"""
# TODO: Provide a better help string, by recommending east help config command, when it
# is implemented


def format_east_yml_load_error_msg(exception_msg):
"""Use this to format error messages that happen when trying to load east.yml"""
return (
Expand All @@ -28,10 +19,19 @@ def format_east_yml_load_error_msg(exception_msg):


def load_east_yml(project_dir: str):
"""Try to load east.yml. If that succeds validate it.
project_dir (str): Path to project directory, where east.yml should be located.
Returns:
dict with east.yml contents if east.yml is found and correctly validated. If it
can not be found it returns None.
"""
east_yml = os.path.join(project_dir, "east.yml")

if not os.path.isfile(east_yml):
raise EastYmlLoadError(east_yml_load_error_msg)
return None

# Validate yaml
schema_yml = os.path.join(os.path.dirname(__file__), "configuration-schema.yaml")
Expand All @@ -55,29 +55,52 @@ def check_duplicated_entries(array_of_dicts, printed_key, subkey):
" in [bold]east.yml[/]!"
)

check_duplicated_entries(east_yml["apps"], "apps", "name")
check_duplicated_entries(east_yml["samples"], "samples", "name")
for app in east_yml["apps"]:
check_duplicated_entries(
app["build-types"], f"{app['name']}.build-types", "type"
# This is needed to discern between apps key present, apps key present, but not set
# and not app key at all.
apps = east_yml.get("apps", -1)

# apps are optional
if apps is not None and apps != -1:
check_duplicated_entries(east_yml["apps"], "apps", "name")
for app in east_yml["apps"]:
check_duplicated_entries(
app["build-types"], f"{app['name']}.build-types", "type"
)

if apps is None:
# Exists, but it was not set
raise EastYmlLoadError(
"[bold]apps[/] key in [bold yellow]east.yml[/] has no apps listed under it!"
)

# For each sample that has inherit key check if that app with that build type exists
for sample in east_yml["samples"]:
if "inherit-build-type" in sample:
inherited_app = sample["inherit-build-type"]["app"]
inherited_type = sample["inherit-build-type"]["build-type"]

app = return_dict_on_match(east_yml["apps"], "name", inherited_app)
if not app:
raise EastYmlLoadError(
f"Sample [bold]{sample['name']}[/] is trying to inherit from a"
f" [bold red]non-existing[/] app [bold]{inherited_app}[/]."
)
if not return_dict_on_match(app["build-types"], "type", inherited_type):
raise EastYmlLoadError(
f"Sample [bold]{sample['name']}[/] is trying to inherit from a"
f" [bold red]non-existing[/] build-type [bold]{inherited_type}[/]."
)
# samples are optional
if east_yml.get("samples"):
check_duplicated_entries(east_yml["samples"], "samples", "name")
# For each sample that has inherit key check if that app with that build type
# exists
for sample in east_yml["samples"]:
if "inherit-build-type" in sample:
# Inherit needs apps
if not east_yml.get("apps"):
raise EastYmlLoadError(
f"Sample [bold]{sample['name']}[/] is trying to inherit, but"
" there are no apps to inherit from!"
)

inherited_app = sample["inherit-build-type"]["app"]
inherited_type = sample["inherit-build-type"]["build-type"]

app = return_dict_on_match(east_yml["apps"], "name", inherited_app)
if not app:
raise EastYmlLoadError(
f"Sample [bold]{sample['name']}[/] is trying to inherit from a"
f" [bold red]non-existing[/] app [bold]{inherited_app}[/]."
)
if not return_dict_on_match(app["build-types"], "type", inherited_type):
raise EastYmlLoadError(
f"Sample [bold]{sample['name']}[/] is trying to inherit from a"
" [bold red]non-existing[/] build-type"
f" [bold]{inherited_type}[/]."
)

return east_yml
24 changes: 19 additions & 5 deletions src/east/workspace_commands/basic_commands.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import os
import shutil as sh

import click

from ..east_context import east_command_settings
Expand All @@ -20,7 +23,15 @@ def clean(east):

@click.command(**east_command_settings)
@click.option("-b", "--board", type=str, help="West board to build for.")
@click.option("-u", "--build-type", type=str, help="Which build type to use.")
@click.option(
"-u",
"--build-type",
type=str,
help=(
"Which build type (a group of [bold]Kconfig[/] fragment files) to use. Requires"
" [bold yellow]east.yml[/] with possible build types."
),
)
@click.option(
"-d",
"--build-dir",
Expand Down Expand Up @@ -60,7 +71,7 @@ def build(east, board, build_type, build_dir, target, source_dir):
For additional info see chapter [bold]Building, Flashing and Debugging[/], section
[bold]One-Time CMake Arguments[/].
\n\n[bold]Note:[/] This command will, after build step, copy [bold]compile_commands.json[/], if found, from the build directory to the project directory. This makes job of locating this file easier for [bold yellow]clangd[/].
\n\n[bold]Note:[/] This command can be only run from inside of a [bold yellow]West workspace[/].
"""
Expand All @@ -71,9 +82,6 @@ def build(east, board, build_type, build_dir, target, source_dir):

if board:
build_cmd += f" -b {board}"
# TODO: Add back build_dir, source_dir and cmake_args options once you make them
# compatible

if build_dir:
build_cmd += f" -d {build_dir}"
if target:
Expand Down Expand Up @@ -102,6 +110,12 @@ def build(east, board, build_type, build_dir, target, source_dir):
# Determine conf files depending on the build type
east.run_west(build_cmd)

compile_file = os.path.join("build", "compile_commands.json")
if os.path.isfile(compile_file):
sh.copyfile(
compile_file, os.path.join(east.project_dir, "compile_commands.json")
)


@click.command(**east_command_settings)
@click.option("-d", "--build-dir", type=str, help="Build directory to create or use.")
Expand Down
79 changes: 59 additions & 20 deletions src/east/workspace_commands/build_type_flag.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,20 @@ def _construct_required_cmake_args(
# We always use common.conf
cmake_args = f"-DCONF_FILE={prefix}conf/common.conf"

# Location of the board file depends on the source_dir and prefix
board_prefix = f"{source_dir}/{prefix}" if source_dir else f"{prefix}"
board_conf = f"{board_prefix}conf/{board}.conf"

overlay_configs = []
# If a west board config file exists then add it first
if os.path.isfile(board_conf):
overlay_configs.append(f"{board}.conf")

# If a west board is given search for board specific config file and add it to the
# the start of overlay_configs, if it is found.
if board:
# Sanitize the board input, user might gave hv version
board = board.split("@")[0]

# Location of the board file depends on the source_dir and prefix
board_prefix = f"{source_dir}/{prefix}" if source_dir else f"{prefix}"
board_conf = f"{board_prefix}conf/{board}.conf"

if os.path.isfile(board_conf):
overlay_configs.append(f"{board}.conf")

# Then add conf_files if there are any
overlay_configs += conf_files
Expand Down Expand Up @@ -103,9 +109,16 @@ def extract(pattern, content):
return cmake_args


build_type_misuse_no_east_yml_msg = """
[bold yellow]east.yml[/] not found in project's root directory, option [bold
cyan]-/u--build-type[/] needs it to determine [bold]Kconfig[/] overlay files, exiting!"""

build_type_misuse_msg = """
\nOption [bold cyan]--build-type[/] can be only given inside of the app, exiting!
"""
Option [bold cyan]--build-type[/] can only be used inside of the application folder, exiting!"""

build_type_misuse_no_app_msg = """
Option [bold cyan]--build-type[/] can only be used when apps key in [bold yellow]east.yml[/] has atleast one
application entry!"""


def no_build_type_msg(build_type):
Expand Down Expand Up @@ -138,29 +151,55 @@ def construct_extra_cmake_arguments(east, build_type, board, build_dir, source_d
Returns: String that should be placed after `--`
"""

if not east.east_yml:
if not build_type:
# east.yml is optional, if it is not present present then default to plain
# west behaviour: no cmake args
return ""
else:
east.print(build_type_misuse_no_east_yml_msg)
east.exit()

# Modify current working dir, if source_dir is used, rstrip is needed cause
# path.join adds one "/" if joning empty string.
source_dir = source_dir if source_dir else ""
cwd = os.path.join(east.cwd, source_dir).rstrip("/")

# Are we inside project_dir and does the relative path contain app/apps or samples
# string
inside_project_dir = is_child_in_parent(east.project_dir, cwd)
# Does the relative path contain app or samples string
relpath = os.path.relpath(cwd, start=east.project_dir)
inside_app = "app" in relpath
inside_sample = "samples" in relpath
app_array = east.east_yml["apps"]
sample_array = east.east_yml["samples"]
if board:
# Sanitize the board input, user might give hv version
board = board.split("@")[0]

if build_type and (not inside_project_dir or not inside_app):
east.print(build_type_misuse_msg)
if not inside_app:
if build_type:
# --build-type can only be given from inside of the project dir
# (--source-dir can be given to point to some app), or directly inside app.
# Any other location is not allowed.
east.print(build_type_misuse_msg)
east.exit()
if not build_type and not inside_sample:
# We are not inside app and not inside sample, no build type was given, we
# are default to plain west behaviour: no cmake args.
return ""

# We get past this point if we are inside app or sample.

# apps field is optional, using build type without that field is however not
# allowed.
app_array = east.east_yml.get("apps")
if build_type and not app_array:
east.print(build_type_misuse_no_app_msg)
east.exit()

# If inside samples determine in which sample are we, get its element
if inside_sample:
# samples key is optional, if it is not present in east_yml then we default to
# plain west behaviour: no cmake args
sample_array = east.east_yml.get("samples")
if not sample_array:
return ""

sample_name = os.path.basename(cwd)
sample_dict = return_dict_on_match(sample_array, "name", sample_name)

Expand All @@ -180,7 +219,7 @@ def construct_extra_cmake_arguments(east, build_type, board, build_dir, source_d
else:
path_prefix = os.path.join(path_to_project_dir, "app", inherited_app)

else:
if inside_app:
# Determine what kind of project it is, single or multi app
if len(app_array) == 1:
app = app_array[0]
Expand Down
Loading

0 comments on commit beb55ae

Please sign in to comment.