Skip to content

Commit

Permalink
Merge pull request #368 from zapta/develop
Browse files Browse the repository at this point in the history
First installment of deprecating the config command. Moved the 'exe' setting to apio.ini
  • Loading branch information
Obijuan authored Apr 5, 2024
2 parents e3e81ff + 8ea213f commit b9ca121
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 70 deletions.
11 changes: 0 additions & 11 deletions apio/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,12 @@
type=click.Choice(["0", "1"]),
help="Verbose mode: `0` General, `1` Information.",
)
@click.option(
"-e",
f"--{EXE}",
type=click.Choice(["default", "native"]),
help="Configure executables: `default` selects apio packages, "
+ "`native` selects system binaries.",
)
def cli(ctx, **kwargs):
"""Apio configuration."""

# -- Extract the arguments
_list = kwargs[LIST]
verbose = kwargs[VERBOSE]
exe = kwargs[EXE]

# -- Access to the profile file
profile = Profile()
Expand All @@ -60,9 +52,6 @@ def cli(ctx, **kwargs):
elif verbose:
profile.add_config("verbose", verbose)

# -- Configure executable mode
elif exe:
profile.add_config("exe", exe)

# -- No paratemers: Show the help
else:
Expand Down
112 changes: 71 additions & 41 deletions apio/managers/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@
# -- Licence GPLv2
"""Utilities for accesing the apio.ini projects"""

# TODO(zapta): Deprecate the mutations of existing api.ini file.

# TODO(zapta): Deprecate the copying of the sconstruct file. This is a developer only
# feature and developers can copy it manually as needed.

import sys
from os.path import isfile
from pathlib import Path

# -- Config Parser: Use INI config files with easy
# https://docs.python.org/3/library/configparser.html
import configparser
from configparser import ConfigParser
import click
from apio import util
from apio.resources import Resources
Expand All @@ -26,10 +31,10 @@ class Project:
"""Class for managing apio projects"""

def __init__(self):
# TODO(zapta): Make these __private and provide getter methods.
self.board = None

# -- Top module by default: main
self.top_module = "main"
self.top_module = None
self.exe_mode = None

def create_sconstruct(self, project_dir: Path, arch=None, sayyes=False):
"""Creates a default SConstruct file"""
Expand Down Expand Up @@ -105,6 +110,7 @@ def create_ini(self, board, top_module, project_dir="", sayyes=False):
# -- Create the apio.ini from scratch
self._create_ini_file(board, top_module, ini_path, PROJECT_FILENAME)

# TODO: Deprecate prgramatic mutations of apio.ini
def update_ini(self, top_module, project_dir):
"""Update the current init file with the given top-module"""

Expand All @@ -123,7 +129,7 @@ def update_ini(self, top_module, project_dir):
return

# -- Read the current apio.ini file
config = configparser.ConfigParser()
config = ConfigParser()
config.read(ini_path)

# -- Set the new top-mddule
Expand All @@ -143,11 +149,11 @@ def update_ini(self, top_module, project_dir):
def _create_ini_file(board, top_module, ini_path, ini_name):
click.secho(f"Creating {ini_name} file ...")
with open(ini_path, "w", encoding="utf8") as file:
config = configparser.ConfigParser()
config = ConfigParser()
config.add_section("env")
config.set("env", "board", board)

# -- Set the top module
# Set the required attributes.
config.set("env", "board", board)
config.set("env", "top-module", top_module)

# -- Write the apio ini file
Expand Down Expand Up @@ -185,53 +191,77 @@ def read(self):
print(f"Info: No {PROJECT_FILENAME} file")
return

# -- Read stored board
board = self._read_board()
# Load the project file.
config_parser = ConfigParser()
config_parser.read(PROJECT_FILENAME)

# -- Read stored top-module
top_module = self._read_top_module()
for section in config_parser.sections():
if section != "env":
print(f"Project file {PROJECT_FILENAME} has an invalid section named [{section}].")
sys.exit(1)

# -- Update board
self.board = board
if not board:
print("Error: invalid {PROJECT_FILENAME} project file")
print("No 'board' field defined in project file")
if "env" not in config_parser.sections():
print(f"Project file {PROJECT_FILENAME} does not have an [env] section.")
sys.exit(1)

# -- Update top-module
self.top_module = top_module
# Parse attributes in the env section.
parsed_attributes = set()
self.board = self._parse_board(config_parser, parsed_attributes)
self.top_module = self._parse_top_module(config_parser, parsed_attributes)
self.exe_mode = self._parse_exe_mode(config_parser, parsed_attributes)

# -- Warn the user the top module has not been set in the apio.ini
# -- file
if not top_module:
click.secho("Warning! No TOP-MODULE in apio.ini", fg="yellow")
# Verify that the project file (api.ini) doesn't contain additional (illegal) keys that
# where not parsed.
for attribute in config_parser.options("env"):
if attribute not in parsed_attributes:
print(f"Project file {PROJECT_FILENAME} contains an unknown attribute '{attribute}'.")
sys.exit(1)

@staticmethod
def _read_board() -> str:
"""Read the configured board from the project file
def _parse_board(config_parser: ConfigParser, parsed_attributes: set[str]) -> str:
"""Parse the configured board from the project file parser and add the keys used
to parsed_attributes.
RETURN:
* A string with the name of the board
"""

config = configparser.ConfigParser()
config.read(PROJECT_FILENAME)
board = config.get("env", "board")

parsed_attributes.add("board")
board = config_parser.get("env", "board")
if not board:
print(f"Error: invalid {PROJECT_FILENAME} project file")
print("No 'board' field defined in [env] section")
sys.exit(1)
return board

@staticmethod
def _read_top_module() -> str:
"""Read the configured top-module from the project file
def _parse_top_module(config_parser: ConfigParser, parsed_attributes: set[str]) -> str:
"""Read the configured top-module from the project file parser and add the keys used
to parsed_attributes.
RETURN:
* A string with the name of the top-module
"""

config = configparser.ConfigParser()
config.read(PROJECT_FILENAME)

try:
top_module = config.get("env", "top-module")
except configparser.NoOptionError:
top_module = None

parsed_attributes.add("top-module")
top_module = config_parser.get("env", "top-module")
if not top_module:
click.secho(f"Warning! invalid {PROJECT_FILENAME} project file", fg="yellow")
click.secho(f"No 'top-module' in [env] section. Assuming 'main'.")
return 'main'
return top_module


@staticmethod
def _parse_exe_mode(config_parser: ConfigParser, parsed_attributes: set[str]) -> str:
"""Read the configured exe mode from the project file parser and add the keys used
to parsed_attributes.
RETURN:
* A string with "default" (default) or "native"
"""
# print(f"*** project.py: reading exe mode")
parsed_attributes.add("exe-mode")
exe_mode = config_parser.get("env", "exe-mode", fallback="default")
if exe_mode not in {"default", "native"}:
print(f"Error: invalid {PROJECT_FILENAME} project file")
print("Optional attribute 'exe-mode' should have the value 'default' or 'native'.")
sys.exit(1)
return exe_mode


10 changes: 7 additions & 3 deletions apio/managers/scons.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from apio.managers.system import System
from apio.profile import Profile
from apio.resources import Resources
from apio.managers.project import Project

# -- Constant for the dictionary PROG, which contains
# -- the programming configuration
Expand All @@ -48,6 +49,10 @@ def __init__(self, project_dir: Path):
If not given, the curent working dir is used
"""

# -- Read the project file (apio.ini)
self.proj = Project()
self.proj.read()

# -- Read the apio profile file
self.profile = Profile()

Expand Down Expand Up @@ -884,9 +889,8 @@ def run(self, command, variables, packages, board=None, arch=None):
click.secho("Info: use custom SConstruct file")

# -- Check the configuration mode
if self.profile.check_exe_default():
if self.proj.exe_mode == "default":
# Run on `default` config mode

# -- Check if the necessary packages are installed
if not util.resolve_packages(
packages,
Expand All @@ -896,7 +900,7 @@ def run(self, command, variables, packages, board=None, arch=None):
# Exit if a package is not installed
raise AttributeError("Package not installed")
else:
click.secho("Info: native config mode")
click.secho("Info: native exe mode")

# -- Execute scons
return self._execute_scons(command, variables, board)
Expand Down
22 changes: 7 additions & 15 deletions apio/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ def __init__(self):

# ---- Set the default parameters
# -- Apio default config mode
self.config = {"exe": "default", "verbose": 0}
self.config = {"verbose": 0}

self.labels = {"exe": "Executable", "verbose": "Verbose"}
self.labels = {"verbose": "Verbose"}

# Apio settings
self.settings = {}
Expand Down Expand Up @@ -73,13 +73,6 @@ def installed_version(self, name: str, version: str):
# -- Package not installed
return False

def check_exe_default(self) -> bool:
"""Check if the exe mode is 'default'"""

is_exe_default = self.config["exe"] == "default"

return is_exe_default

def add_package(self, name: str, version: str):
"""Add a package to the profile class"""

Expand Down Expand Up @@ -164,8 +157,6 @@ def _load_profile(self, profile: Path):
if "config" in data.keys():
self.config = data["config"]

if "exe" not in self.config.keys():
self.config["exe"] = "default"

if "verbose" not in self.config.keys():
self.config["verbose"] = 0
Expand Down Expand Up @@ -204,8 +195,9 @@ def list(self):
for key in self.config:

# -- Print the parameter
click.secho(
f"{self.labels[key]} mode: {self.config[key]}",
fg="yellow",
)
if key in self.labels:
click.secho(
f"{self.labels[key]} mode: {self.config[key]}",
fg="yellow",
)
print()

0 comments on commit b9ca121

Please sign in to comment.