Files
cariflex/tools/EVerest-main/lib/everest/framework/bazel/everest_env.bzl
Eric F d398a6ced2 Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
2026-06-08 00:38:27 -04:00

308 lines
9.6 KiB
Python

load("@rules_python//python:defs.bzl", "PyInfo")
load("//third-party/bazel/toolchains:defs.bzl", "CROSS_PYTHON_INCOMPATIBLE")
def _everest_env(ctx):
"""Everest Root rule
Rule creates a everest root from provided modules and config file.
"""
# Validate the input - we make sure that the set of provided modules matches
# the set of modules declared in config.yaml
validation_output = ctx.actions.declare_file(ctx.attr.name + ".validation")
ctx.actions.run(
inputs = ctx.attr.config_file[DefaultInfo].files,
outputs = [validation_output],
executable = ctx.executable._validation_tool,
arguments = [
"--output",
validation_output.path,
"--config",
ctx.attr.config_file[DefaultInfo].files.to_list()[0].path,
"--",
] +
[mod.label.name for mod in ctx.attr.modules],
)
symlinks = {}
files = []
py_toolchain = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"]
py_interpreter = py_toolchain.py3_runtime.interpreter.dirname.removeprefix("external/")
py_imports = []
py_transitive_sources = []
# Python modules get a special handling.
for mod in ctx.attr.modules + ctx.attr.test_modules:
if PyInfo in mod:
py_imports.extend(mod[PyInfo].imports.to_list())
py_transitive_sources.extend(mod[PyInfo].transitive_sources.to_list())
for mod in ctx.attr.modules + ctx.attr.test_modules:
# Find the manifest in the data_runfiles and use its path as prefix.
manifest = [
file
for file in mod[DefaultInfo].data_runfiles.files.to_list()
if file.basename in ["manifest.yaml", "manifest.yml"]
][0]
prefix = manifest.dirname
symlinks.update(
{
"libexec/everest/modules/{0}{1}".format(
mod.label.name,
file.path.removeprefix(prefix),
): file
for file in mod[DefaultInfo].data_runfiles.files.to_list()
if file.path.startswith(prefix)
},
)
[
files.append(file)
for file in mod[DefaultInfo].default_runfiles.files.to_list()
if not file.path.startswith(prefix)
]
config_file = ctx.attr.config_file[DefaultInfo].files.to_list()[0]
config_path = "etc/everest/{0}".format(config_file.basename)
symlinks.update({"bin/manager_impl": ctx.attr.manager[DefaultInfo].files.to_list()[0]})
symlinks.update(
{
config_path: config_file,
},
)
symlinks.update(
{
"etc/everest/default_logging.cfg": ctx.attr.default_logging_file[DefaultInfo].files.to_list()[0],
},
)
# EVerest expects that there is a `share/everest/www` directory but does
# not care about the content... We just symlink the config.yaml into it.
symlinks.update(
{
"share/everest/www/config.yaml": ctx.attr.config_file[DefaultInfo].files.to_list()[0],
},
)
symlinks.update(
{
"share/everest/schemas/{0}".format(file.basename): file
for file in ctx.attr.schemas[DefaultInfo].files.to_list()
},
)
symlinks.update(
{
"share/everest/interfaces/{0}".format(file.basename): file
for interfaces in ctx.attr.interfaces
for file in interfaces[DefaultInfo].files.to_list()
},
)
symlinks.update(
{
"share/everest/types/{0}".format(file.basename): file
for types in ctx.attr.types
for file in types[DefaultInfo].files.to_list()
},
)
symlinks.update(
{
"share/everest/errors/{0}".format(file.basename): file
for errors in ctx.attr.errors
for file in errors[DefaultInfo].files.to_list()
},
)
# For the executable we need to export the python specific variables by
# hand.
script = ctx.actions.declare_file("manager_wrapper.{}".format(ctx.label.name))
script_content = """\
#!/bin/sh
set -eu
SCRIPT_DIR=$(cd "$(dirname "$0")/.." && pwd)
export PATH="$SCRIPT_DIR/{py_interpreter}:$PATH"
{pythonpath_lines}
""".format(
py_interpreter = py_interpreter.removeprefix("external/"),
pythonpath_lines = "\n".join([
'export PYTHONPATH="$SCRIPT_DIR/{0}:$PYTHONPATH"'.format(imp)
for imp in py_imports
]),
)
if ctx.attr._is_test:
script_content += """
exec bin/manager_impl --prefix . --config {0} --check
""".format(config_path)
else:
script_content += """
if [ $# -gt 0 ]; then
exec bin/manager_impl "$@"
else
exec bin/manager_impl --prefix . --config {0}
fi
""".format(config_path)
ctx.actions.write(script, script_content, is_executable = True)
symlinks.update({"bin/manager": script})
runfiles = ctx.runfiles(
symlinks = symlinks,
files = files + [script],
)
return [
DefaultInfo(
executable = script,
runfiles = runfiles,
),
OutputGroupInfo(_validation = depset([validation_output])),
PyInfo(
imports = depset(py_imports),
transitive_sources = depset(py_transitive_sources),
),
]
ATTRS = {
"config_file": attr.label(
doc = """
The EVerest configuration file. It will be linked to
`/etc/everest/<basename>`""",
allow_single_file = True,
),
"manager": attr.label(
doc = "The EVerest manager.",
default = Label("//lib/everest/framework:manager"),
allow_single_file = True,
executable = True,
cfg = "target",
),
"schemas": attr.label(
doc = "The target with the EVerest schemas.",
default = Label("//lib/everest/framework/schemas"),
),
"interfaces": attr.label_list(
doc = "A list of targets with EVerest interfaces.",
default = [
Label("//lib/everest/framework/everestrs/tests/interfaces"),
],
),
"types": attr.label_list(
doc = "A list of targets with EVerest types.",
default = [
Label("//lib/everest/framework/everestrs/tests/types"),
],
),
"errors": attr.label_list(
doc = "A list of targets with EVerest errors.",
default = [
Label("//lib/everest/framework/everestrs/tests/errors"),
],
),
"default_logging_file": attr.label(
doc = "The target with the EVerest logging.ini file.",
default = Label("//lib/everest/framework/everestrs/tests:logging.ini"),
allow_single_file = True,
),
"modules": attr.label_list(
doc = """
The list of targets with the EVerest modules under test.
The rule validates that the set of provided modules matches the set of modules
defined in the given `config_file`.""",
allow_files = False,
),
"test_modules": attr.label_list(
doc = """
The list of targets with EVerest modules which are only enabled by the
`everest.testing` framework.
The rule will not enforce that these modules are defined in the given
`config_file`.
""",
allow_files = False,
),
"_validation_tool": attr.label(
default = Label("//lib/everest/framework/bazel/validate"),
executable = True,
cfg = "exec",
),
"_is_test": attr.bool(
default = False,
doc = "Indicates if target is test target to validate config",
),
}
everest_impl_env = rule(
implementation = _everest_env,
attrs = ATTRS,
executable = True,
toolchains = ["@bazel_tools//tools/python:toolchain_type"],
)
_everest_impl_test = rule(
implementation = _everest_env,
attrs = dict(ATTRS, _is_test = attr.bool(default = True)),
toolchains = ["@bazel_tools//tools/python:toolchain_type"],
doc = """
Creates an EVerest Test.
Example:
Suppose you have the EVerest modules `ModuleFoo` and `ModuleBar` and the
EVerest config `my_config.yaml` which uses both modules. The test will launch
the modules and return when the manager process returns.
Then you can create an environment by writing:
```
everest_test(
name = "my_everest_env",
modules = [":ModuleFoo", ":ModuleBar"],
config_file = ":my_config.yaml",
test_script=":my_test_script",
)
```
You can run it with `bazel test`.
""",
test = True,
)
def everest_test(name, target_compatible_with = [], **kwargs):
"""Wrapper around the everest_test rule that marks the target as
incompatible with cross-compilation platforms (no Python toolchain)."""
_everest_impl_test(
name = name,
target_compatible_with = CROSS_PYTHON_INCOMPATIBLE + target_compatible_with,
**kwargs
)
def everest_env(name, target_compatible_with = [], **kwargs):
"""
Creates an EVerest environment.
Example:
Suppose you have the EVerest modules `ModuleFoo` and `ModuleBar` and the
EVerest config `my_config.yaml` which uses both modules.
Then you can create an environment by writing:
```
everest_env(
name = "my_everest_env",
modules = [":ModuleFoo", ":ModuleBar"],
config_file = ":my_config.yaml",
)
```
You can either run this target with `bazel run` or pass it for example to a (py)
test which will run your tests against the environment.
"""
everest_impl_env(
name = name,
target_compatible_with = CROSS_PYTHON_INCOMPATIBLE + target_compatible_with,
**kwargs
)
everest_test(name = name + "__manager_test", tags = ["exclusive"], target_compatible_with = target_compatible_with, **kwargs)