diff --git a/apio/commands/install.py b/apio/commands/install.py index bf11fb89..14adf7d9 100644 --- a/apio/commands/install.py +++ b/apio/commands/install.py @@ -70,7 +70,6 @@ def install_packages( @options.all_option_gen(help="Install all packages.") @options.force_option_gen(help="Force the packages installation.") @options.project_dir_option -@options.platform_option @options.verbose_option def cli( ctx: Context, @@ -80,7 +79,6 @@ def cli( list_: bool, all_: bool, force: bool, - platform: str, project_dir: Path, verbose: bool, ): @@ -99,7 +97,6 @@ def cli( # -- Load the resources. We don't care about project specific resources. resources = Resources( - platform_id_override=platform, project_dir=project_dir, project_scope=False, ) diff --git a/apio/commands/options.py b/apio/commands/options.py index 3257153a..8cf9611f 100644 --- a/apio/commands/options.py +++ b/apio/commands/options.py @@ -196,17 +196,6 @@ def pack_option_gen( ) -# -- NOTE: Not using -p to avoid conflict with --project-dir. -platform_option = click.option( - "platform", # Var name. - "--platform", - type=str, - metavar="platform_id", - help=("(Advanced, for developers) Platform id override."), - cls=cmd_util.ApioOption, -) - - project_dir_option = click.option( "project_dir", # Var name. "-p", diff --git a/apio/commands/packages.py b/apio/commands/packages.py index 0e66e6f4..b56d35b5 100644 --- a/apio/commands/packages.py +++ b/apio/commands/packages.py @@ -193,7 +193,6 @@ def _list(resources: Resources, verbose: bool) -> int: @fix_option @options.force_option_gen(help="Force installation.") @options.project_dir_option -@options.platform_option @options.sayyes @options.verbose_option def cli( @@ -206,7 +205,6 @@ def cli( uninstall: bool, fix: bool, force: bool, - platform: str, project_dir: Path, sayyes: bool, verbose: bool, @@ -227,7 +225,6 @@ def cli( # -- Load the resources. We don't care about project specific resources. resources = Resources( - platform_id_override=platform, project_dir=project_dir, project_scope=False, ) diff --git a/apio/commands/system.py b/apio/commands/system.py index 65f3eccb..9d88ba76 100644 --- a/apio/commands/system.py +++ b/apio/commands/system.py @@ -76,10 +76,12 @@ apio system --lsusb # List USB devices apio system --lsserial # List serial devices apio system --info # Show platform id and info. - apio system --platforms # Show supported platforms The flags --lstdi, --lsusb, --lsserial, and --info are exclusive and cannot be mixed in the same command. + +[Advanced] The system configuration can be overriden using the system env +variable APIO_HOME_DIR, APIO_PACKAGES_DIR, APIO_PLATFORM. """ diff --git a/apio/commands/uninstall.py b/apio/commands/uninstall.py index 84dbdbee..77e0a7f1 100644 --- a/apio/commands/uninstall.py +++ b/apio/commands/uninstall.py @@ -66,7 +66,6 @@ def _uninstall(packages: list, resources: Resources, sayyes, verbose: bool): @options.list_option_gen(help="List all installed packages.") @options.all_option_gen(help="Uninstall all packages.") @options.project_dir_option -@options.platform_option @options.sayyes @options.verbose_option def cli( @@ -77,7 +76,6 @@ def cli( list_: bool, all_: bool, project_dir: Path, - platform: str, sayyes: bool, verbose: bool, ): @@ -94,7 +92,6 @@ def cli( # -- Load the resources. resources = Resources( - platform_id_override=platform, project_dir=project_dir, project_scope=False, ) diff --git a/apio/env_options.py b/apio/env_options.py new file mode 100644 index 00000000..91292d6a --- /dev/null +++ b/apio/env_options.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# -- This file is part of the Apio project +# -- (C) 2016-2018 FPGAwars +# -- Author Jesús Arroyo +# -- Licence GPLv2 +# -- Derived from: +# ---- Platformio project +# ---- (C) 2014-2016 Ivan Kravets +# ---- Licence Apache v2 +"""Functions for reading the APIO env options. This are system env +variables that are used to modify the default behavior of APIO. +""" + +import os +from typing import List + +# -- Env variable to override the apio home dir ~/.apio. If specified, +# -- it will contains the profile.json file and if APIO_PACKAGES_DIR is not +# -- specified, the 'packages' directory with the individual packages. +APIO_HOME_DIR = "APIO_HOME_DIR" + +# -- Env variable to override the apio packages dir ~/.apio/packages. +# -- If specified, it contains the installed packages directories such as +# -- 'examples' or 'tools-oss-cad-suite. +APIO_PACKAGES_DIR = "APIO_PACKAGES_DIR" + +# -- Env variable to override the platform id that is determined automatically +# -- from the system properties. If specified, the value should match one +# -- of the platforms specified in resources/platforms.json. +APIO_PLATFORM = "APIO_PLATFORM" + +# -- List of all supported env options. +_SUPPORTED_APIO_VARS = [ + APIO_HOME_DIR, + APIO_PACKAGES_DIR, + APIO_PLATFORM, +] + + +def get(var_name: str, default: str = None): + """Return the given APIO config env value or default if not found. + var_name must start with 'APIO_' and match _API_ENV_NAME_REGEX. + """ + + # -- Sanity check. To make sure we are aware of all the vars used. + assert ( + var_name in _SUPPORTED_APIO_VARS + ), f"Unknown apio env var '{var_name}'" + + # -- Get the value, None if not defined. + var_value = os.getenv(var_name) + + if var_value is None: + # -- Var is undefied. Use default + var_value = default + else: + # -- Var is defined. For windows benefit, remove optional quotes. + if var_value.startswith('"') and var_value.endswith('"'): + var_value = var_value[1:-1] + + return var_value + + +def get_defined() -> List[str]: + """Return the list of apio env options vars that are defined.""" + result = [] + for var in _SUPPORTED_APIO_VARS: + if get(var): + result.append(var) + return result diff --git a/apio/managers/old_installer.py b/apio/managers/old_installer.py index b7ff9a40..7718d99c 100644 --- a/apio/managers/old_installer.py +++ b/apio/managers/old_installer.py @@ -84,6 +84,10 @@ def __init__( self.packages_dir = "" # -- Folder name were the packages are stored + # -- + # -- NOTE: we shouldn't assume the directory name since it can be + # -- overriden with APIO_PACKAGES_DIR but since this old installer is + # -- going away, we leave this as is. (Nov 2024) dirname = "packages" # -- If the package is known... diff --git a/apio/managers/scons.py b/apio/managers/scons.py index b5e199c9..2b70736e 100644 --- a/apio/managers/scons.py +++ b/apio/managers/scons.py @@ -154,6 +154,7 @@ def lint(self, args) -> int: "nowarn": args.get("nowarn"), "warn": args.get("warn"), "nostyle": args.get("nostyle"), + "platform_id": self.resources.platform_id, } ) return self._run( diff --git a/apio/resources.py b/apio/resources.py index 022f81a6..934ac9b1 100644 --- a/apio/resources.py +++ b/apio/resources.py @@ -14,7 +14,7 @@ from pathlib import Path from typing import Optional, Dict import click -from apio import util +from apio import util, env_options from apio.profile import Profile @@ -82,7 +82,6 @@ def __init__( self, *, project_scope: bool, - platform_id_override: str = "", project_dir: Optional[Path] = None, ): """Initializes the Resources object. 'project dir' is an optional path @@ -93,6 +92,15 @@ def __init__( 'apio packages' uses the global scope while commands such as 'apio build' use the project scope. """ + + # -- Inform as soon as possible about the list of apio env options + # -- that modify its default behavior. + defined_env_options = env_options.get_defined() + if defined_env_options: + click.secho( + f"Active env options {defined_env_options}.", fg="yellow" + ) + # -- Maps the optional project_dir option to a path. self.project_dir: Path = util.get_project_dir(project_dir) @@ -103,9 +111,7 @@ def __init__( self.platforms = self._load_resource(PLATFORMS_JSON) # -- Determine the platform_id for this APIO session. - self.platform_id = self._determine_platform_id( - platform_id_override, self.platforms - ) + self.platform_id = self._determine_platform_id(self.platforms) # -- Read the apio packages information self.all_packages = self._load_resource(PACKAGES_JSON) @@ -579,12 +585,11 @@ def list_fpgas(self): click.secho(f"Total: {len(self.fpgas)} fpgas\n") @staticmethod - def _determine_platform_id( - platform_id_override: str, platforms: Dict[str, Dict] - ) -> str: + def _determine_platform_id(platforms: Dict[str, Dict]) -> str: """Determines and returns the platform io based on system info and optional override.""" # -- Use override and get from the underlying system. + platform_id_override = env_options.get(env_options.APIO_PLATFORM) if platform_id_override: platform_id = platform_id_override else: diff --git a/apio/util.py b/apio/util.py index fe19752c..331f994e 100644 --- a/apio/util.py +++ b/apio/util.py @@ -22,6 +22,7 @@ import click from serial.tools.list_ports import comports import requests +from apio import env_options # ---------------------------------------- # -- Constants @@ -150,39 +151,6 @@ def get_path_in_apio_package(subpath: str) -> Path: return path -def get_projconf_option_dir(name: str, default=None): - """Return the project option with the given name - These options are place either on environment variables or - into the /etc/apio.json file in the case of debian distributions - - All the APIO environment variables have the prefix "APIO_" - - Project options: - - * home_dir : APIO home directory - """ - - # -- Get the full name of the environment variable - _env_name = f"APIO_{name.upper()}" - - # -- Check if the environment variable - # -- is defined - if _env_name in os.environ: - # -- Read the value of the environmental variable - _env_value = os.getenv(_env_name) - - # -- On window systems the environmental variables can - # -- include the quotes (""). But not in Linux - # -- If there are quotes, remove them - if _env_value.startswith('"') and _env_value.endswith('"'): - _env_value = _env_value[1:-1] - - return _env_value - - # -- Return the default home_dir - return default - - def get_home_dir() -> Path: """Get the APIO Home dir. This is the apio folder where the profle is located and the packages installed. The APIO Home dir can be set in the @@ -195,7 +163,9 @@ def get_home_dir() -> Path: # -- Get the APIO_HOME_DIR env variable # -- It returns None if it was not defined - apio_home_dir_env = get_projconf_option_dir("home_dir") + apio_home_dir_env = env_options.get( + env_options.APIO_HOME_DIR, default=None + ) # -- Get the home dir. It is what the APIO_HOME_DIR env variable # -- says, or the default folder if None @@ -219,7 +189,7 @@ def get_packages_dir() -> Path: """Return the base directory of apio packages. Packages are installed in the following folder: * Default: $APIO_HOME_DIR/packages - * $APIO_PKG_DIR/packages: if the APIO_PKG_DIR env variable is set + * $APIO_PACKAGES_DIR: if the APIO_PACKAGES_DIR env variable is set * INPUT: - pkg_name: Package name (Ex. 'examples') * OUTPUT: @@ -228,30 +198,21 @@ def get_packages_dir() -> Path: - or None if the packageis not installed """ - # -- Get the apio home dir: - # -- Ex. '/home/obijuan/.apio' - apio_home_dir = get_home_dir() - - # -- Get the APIO_PKG_DIR env variable + # -- Get the APIO_PACKAGES_DIR env variable # -- It returns None if it was not defined - apio_pkg_dir_env = get_projconf_option_dir("pkg_dir") + packaged_dir_override = env_options.get(env_options.APIO_PACKAGES_DIR) - # -- Get the pkg base dir. It is what the APIO_PKG_DIR env variable - # -- says, or the default folder if None - if apio_pkg_dir_env: - pkg_home_dir = Path(apio_pkg_dir_env) + # -- If specified, use the override. + if packaged_dir_override: + pkg_home_dir = Path(packaged_dir_override) - # -- Default value + # -- Else, use the default value. else: - pkg_home_dir = apio_home_dir - - # -- Create the package folder - # -- Ex '/home/obijuan/.apio/packages/tools-oss-cad-suite' - package_dir = pkg_home_dir / "packages" + # -- Ex '/home/obijuan/.apio/packages/tools-oss-cad-suite' + pkg_home_dir = get_home_dir() / "packages" # -- Return the folder if it exists - # if package_dir.exists(): - return package_dir + return pkg_home_dir def call(cmd): diff --git a/test/conftest.py b/test/conftest.py index 620cf4ab..6345002b 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -38,18 +38,18 @@ def decorator(): # -- Set a strange directory for executing # -- apio: it contains spaces and unicode characters # -- for testing. It should work - cwd = str(Path.cwd() / " ñ") + cwd = Path.cwd() / " ñ" # -- Debug if DEBUG: print("") print(" --> configenv():") - print(f" apio working directory: {cwd}") + print(f" apio working directory: {str(cwd)}") # -- Set the apio home dir and apio packages dir to # -- this test folder - environ["APIO_HOME_DIR"] = cwd - environ["APIO_PKG_DIR"] = cwd + environ["APIO_HOME_DIR"] = str(cwd) + environ["APIO_PACKAGES_DIR"] = str(cwd / "packages") environ["TESTING"] = "" return decorator diff --git a/test/test_end_to_end.py b/test/test_end_to_end.py index e26f2bcd..8625c561 100644 --- a/test/test_end_to_end.py +++ b/test/test_end_to_end.py @@ -85,18 +85,12 @@ def test_end_to_end1(clirunner, validate_cliresult, configenv, offline): assert "Installing package 'examples'" in result.output assert "was already installed" in result.output - # -- Execute - # -- "apio packages - # -- --install examples - # -- --platform windows_amd64 - # -- --force" + # -- Execute "apio packages --install examples --force" result = clirunner.invoke( cmd_packages, [ "--install", "examples", - "--platform", - "windows_amd64", "--force", ], ) @@ -105,7 +99,7 @@ def test_end_to_end1(clirunner, validate_cliresult, configenv, offline): assert "Download" in result.output assert "Package 'examples' installed successfully" in result.output - # -- Execute "apio packages --install --list" + # -- Execute "apio packages --list" result = clirunner.invoke(cmd_packages, ["--list"]) assert result.exit_code == 0, result.output assert "No errors" in result.output