Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Environment rework #95

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions mlonmcu/cli/helper/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ def extract_frontend_names(args, context=None):
# No need to specify a default, because we just use the provided order in the environment.yml
assert frontend_names is None, "TODO"
assert context is not None, "Need context to resolve default frontends"
all_frontend_names = context.environment.lookup_frontend_configs(names_only=True)
names.extend(all_frontend_names)
default_frontend_names = context.environment.get_used_frontends()
names.extend(default_frontend_names)
return names


Expand Down Expand Up @@ -155,5 +155,5 @@ def extract_platform_names(args, context=None):
assert args.platform is None
if context is None:
return [None]
platforms = context.environment.lookup_platform_configs(names_only=True)
platforms = context.environment.get_used_platforms()
return platforms
18 changes: 9 additions & 9 deletions mlonmcu/context/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@
from mlonmcu.plugins import process_extensions
from mlonmcu.context.read_write_filelock import ReadFileLock, WriteFileLock, RWLockTimeout

from mlonmcu.environment.environment import Environment, UserEnvironment
from mlonmcu.environment.user_environment import UserEnvironment

from mlonmcu.environment.list import get_environments_map
from mlonmcu.environment.config import get_environments_dir, get_plugins_dir

logger = get_logger()


def lookup_environment() -> Environment:
def lookup_environment() -> "UserEnvironment":
"""Helper function to automatically find a suitable environment.

This function is used if neither a name nor a path of the environment was specified by the user.
Expand Down Expand Up @@ -85,7 +85,7 @@ def lookup_environment() -> Environment:
return None


def get_environment_by_path(path: Union[str, Path]) -> Environment:
def get_environment_by_path(path: Union[str, Path]) -> UserEnvironment:
"""Utility to find an environment file using a supplied path.

Parameters
Expand All @@ -95,7 +95,7 @@ def get_environment_by_path(path: Union[str, Path]) -> Environment:

Returns
-------
Environment:
UserEnvironment:
The environment (if the lookup was successful).
"""
if isinstance(path, str):
Expand All @@ -108,7 +108,7 @@ def get_environment_by_path(path: Union[str, Path]) -> Environment:
return None


def get_environment_by_name(name: str) -> Environment:
def get_environment_by_name(name: str) -> UserEnvironment:
"""Utility to find an environment file using a supplied name.

Parameters
Expand Down Expand Up @@ -149,12 +149,12 @@ def get_ids(directory: Path) -> List[int]:
return sorted(ids) # TODO: sort by session datetime?


def load_recent_sessions(env: Environment, count: int = None) -> List[Session]:
def load_recent_sessions(env: UserEnvironment, count: int = None) -> List[Session]:
"""Get a list of recent sessions for the environment.

Parameters
----------
env : Environment
env : UserEnvironment
MLonMCU environment which should be used.
count : int
Maximum number of sessions to return. Collect all if None.
Expand Down Expand Up @@ -234,7 +234,7 @@ def setup_logging(environment):

Attributes
----------
environment : Environment
environment : UserEnvironment
The MLonMCU Environment where paths, repos, features,... are configured.
"""
defaults = environment.defaults
Expand All @@ -255,7 +255,7 @@ class MlonMcuContext:

Attributes
----------
environment : Environment
environment : UserEnvironment
The MLonMCU Environment where paths, repos, features,... are configured.
deps_lock : str ("read" or "write" default "write")
Read means that the program does not write to the ./deps folder in the env folder.
Expand Down
96 changes: 3 additions & 93 deletions mlonmcu/environment/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import os
import xdg
import logging
from collections import namedtuple
from enum import Enum
from pathlib import Path

Expand Down Expand Up @@ -88,18 +89,12 @@ def __init__(
log_level=logging.INFO,
log_to_file=False,
log_rotate=False,
default_framework=None,
default_backends={},
default_target=None,
cleanup_auto=False,
cleanup_keep=100,
):
self.log_level = log_level
self.log_to_file = log_to_file
self.log_rotate = log_rotate
self.default_framework = default_framework
self.default_backends = default_backends
self.default_target = default_target
self.cleanup_auto = cleanup_auto
self.cleanup_keep = cleanup_keep

Expand All @@ -125,90 +120,5 @@ def __repr(self):
return f"PathConfig({self.path})"


class RepoConfig(BaseConfig):
def __init__(self, url, ref=None):
self.url = url
self.ref = ref


class BackendConfig(BaseConfig):
def __init__(self, name, enabled=True, features={}):
self.name = name
self.enabled = enabled
self.features = features


class FeatureKind(Enum):
UNKNOWN = 0
FRAMEWORK = 1
BACKEND = 2
TARGET = 3
FRONTEND = 4


class FeatureConfig:
def __init__(self, name, kind=FeatureKind.UNKNOWN, supported=True):
self.name = name
self.supported = supported

def __repr__(self):
return self.__class__.__name__ + "(" + str(vars(self)) + ")"


class FrameworkFeatureConfig(FeatureConfig):
def __init__(self, name, framework, supported=True):
super().__init__(name=name, kind=FeatureKind.FRONTEND, supported=supported)
self.framework = framework


class BackendFeatureConfig(FeatureConfig):
def __init__(self, name, backend, supported=True):
super().__init__(name=name, kind=FeatureKind.FRONTEND, supported=supported)
self.backend = backend


class PlatformFeatureConfig(FeatureConfig):
def __init__(self, name, platform, supported=True):
super().__init__(name=name, kind=FeatureKind.TARGET, supported=supported)
self.platform = platform


class TargetFeatureConfig(FeatureConfig):
def __init__(self, name, target, supported=True):
super().__init__(name=name, kind=FeatureKind.TARGET, supported=supported)
self.target = target


class FrontendFeatureConfig(FeatureConfig):
def __init__(self, name, frontend, supported=True):
super().__init__(name=name, kind=FeatureKind.FRONTEND, supported=supported)
self.frontend = frontend


class FrameworkConfig(BaseConfig):
def __init__(self, name, enabled=True, backends={}, features={}):
self.name = name
self.enabled = enabled
self.backends = backends
self.features = features


class FrontendConfig(BaseConfig):
def __init__(self, name, enabled=True, features={}):
self.name = name
self.enabled = enabled
self.features = features


class PlatformConfig(BaseConfig):
def __init__(self, name, enabled=True, features={}):
self.name = name
self.enabled = enabled
self.features = features


class TargetConfig(BaseConfig):
def __init__(self, name, enabled=True, features={}):
self.name = name
self.enabled = enabled
self.features = features
RepoConfig = namedtuple("RepoConfig", "url ref", defaults=[None, None])
ComponentConfig = namedtuple("ComponentConfig", "supported used", defaults=[False, False])
165 changes: 165 additions & 0 deletions mlonmcu/environment/convert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#
# Copyright (c) 2022 TUM Department of Electrical and Computer Engineering.
#
# This file is part of MLonMCU.
# See https://github.com/tum-ei-eda/mlonmcu.git for further info.
#
# 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.
#
# import yaml
# import pathlib
# import logging
#
# from .config import PathConfig


import argparse
from mlonmcu.environment.legacy.environment import UserEnvironment as UserEnvironmentOld
from mlonmcu.environment.user_environment import UserEnvironment
from mlonmcu.environment.config import ComponentConfig, DefaultsConfig

# from mlonmcu.environment.loader import load_environment_from_file


def convert_v1_to_v2(env):
frameworks = {f.name: ComponentConfig(f.enabled, f.name == env.defaults.default_framework) for f in env.frameworks}
backends = {
b.name: ComponentConfig(
b.enabled, f.name == env.defaults.default_framework and b.name == env.defaults.default_backends[f.name]
)
for f in env.frameworks
for b in f.backends
if f.enabled
}
toolchains = {t: ComponentConfig(True, False) for t in env.toolchains}
frontends = {f.name: ComponentConfig(f.enabled, f.enabled) for f in env.frontends}
platforms = {p.name: ComponentConfig(p.enabled, p.enabled) for p in env.platforms}
targets = {t.name: ComponentConfig(t.enabled, t.name == env.defaults.default_target) for t in env.targets}

framework_features = {
f_.name: ComponentConfig(f_.supported, False) for f in env.frameworks for f_ in f.features if f.enabled
}
backend_features = {
f_.name: ComponentConfig(f_.supported, False)
for f in env.frameworks
for b in f.backends
for f_ in b.features
if b.enabled and f.enabled
}
target_features = {
f_.name: ComponentConfig(f_.supported, False) for t in env.targets for f_ in t.features if t.enabled
}
platform_features = {
f_.name: ComponentConfig(f_.supported, False) for p in env.platforms for f_ in p.features if p.enabled
}
frontend_features = {
f_.name: ComponentConfig(f_.supported, False) for f in env.frontends for f_ in f.features if f.enabled
}
other_features = {}

def helper(name):
return any(
[
name in x and x[name].supported
for x in [
framework_features,
backend_features,
target_features,
platform_features,
frontend_features,
other_features,
]
]
)

all_feature_names = (
set(framework_features.keys())
.union(set(backend_features.keys()))
.union(set(target_features.keys()))
.union(set(platform_features.keys()))
.union(set(frontend_features.keys()))
.union(set(other_features.keys()))
)
features = {name: ComponentConfig(helper(name), False) for name in all_feature_names}

env2 = UserEnvironment(
env.home,
alias=env.alias,
defaults=DefaultsConfig(
log_level=env.defaults.log_level,
log_to_file=env.defaults.log_to_file,
log_rotate=env.defaults.log_rotate,
cleanup_auto=env.defaults.cleanup_auto,
cleanup_keep=env.defaults.cleanup_keep,
),
paths=env.paths,
repos=env.repos,
frameworks=frameworks,
backends=backends,
frontends=frontends,
platforms=platforms,
toolchains=toolchains,
targets=targets,
features=features,
# postprocesses=None,
variables=env.vars,
default_flags=env.flags,
)
return env2


def main():
parser = argparse.ArgumentParser(
description=f"Converter for environment files/templates",
)
parser.add_argument("input", metavar="FILE", type=str, nargs=1, help="File to process")
parser.add_argument(
"--output",
"-o",
metavar="DEST",
type=str,
default=None,
help="""Output directory/file (default: print to stdout instead)""",
)
parser.add_argument(
"--in-version",
metavar="VER",
type=int,
default=1,
help="""Output directory/file (default: %(default)s)""",
)
parser.add_argument(
"--out-version",
metavar="VER",
type=int,
default=2,
help="""Output directory/file (default: %(default)s)""",
)
args = parser.parse_args()

assert args.in_version == 1 and args.out_version == 2, "Unsupported combination of versions"

file = args.input[0]

env = UserEnvironmentOld.from_file(file)

env2 = convert_v1_to_v2(env)

if args.output:
env2.to_file(args.output)
else:
print(env2.to_text())


if __name__ == "__main__":
main()
Loading