diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..95ff315 --- /dev/null +++ b/.flake8 @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2026 Igalia S.L. +# SPDX-License-Identifier: MIT + +[flake8] +max-line-length = 140 +doctests = True +exclude = .git, .eggs, __pycache__, build/, dist/ +ignore = F824, W504 diff --git a/.github/workflows/python-lint.yml b/.github/workflows/python-lint.yml new file mode 100644 index 0000000..7939992 --- /dev/null +++ b/.github/workflows/python-lint.yml @@ -0,0 +1,30 @@ +name: Python Linting + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - name: Set up environment + run: | + sudo apt update + sudo apt install python3-pip + sudo pip3 install --break-system-packages flake8 mypy + + - name: Flake8 + run: | + python3 -m flake8 src + + - name: MyPy + run: | + python3 -m mypy src diff --git a/.github/workflows/reuse-lint.yml b/.github/workflows/reuse-lint.yml new file mode 100644 index 0000000..be08489 --- /dev/null +++ b/.github/workflows/reuse-lint.yml @@ -0,0 +1,26 @@ +name: License Linting + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - name: Set up environment + run: | + sudo apt update + sudo apt install python3-pip + sudo pip3 install --break-system-packages reuse + + - name: REUSE + run: | + python3 -m reuse lint diff --git a/REUSE.toml b/REUSE.toml index 954a802..2958913 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -1,28 +1,28 @@ version = 1 SPDX-PackageName = "moonforge-cli" -SPDX-PackageSupplier = "The Moonforge Project" +SPDX-PackageSupplier = "Igalia S.L." SPDX-PackageDownloadLocation = "https://github.com/moonforgelinux/moonforge-cli" [[annotations]] -path = "README.md" +path = ".github/workflows/*.yml" precedence = "aggregate" -SPDX-FileCopyrightText = "2026 Igalia S.L." -SPDX-License-Identifier = "CC0-1.0" +SPDX-FileCopyrightText = "2026 Igalia S.L." +SPDX-License-Identifier = "MIT" [[annotations]] -path = "CHANGELOG.md" +path = ["CHANGELOG.md", "README.md"] precedence = "aggregate" -SPDX-FileCopyrightText = "2026 Igalia S.L." +SPDX-FileCopyrightText = "2026 Igalia S.L." SPDX-License-Identifier = "CC0-1.0" [[annotations]] path = "pyproject.toml" precedence = "aggregate" -SPDX-FileCopyrightText = "2026 Igalia S.L." -SPDX-License-Identifier = "CC0-1.0" +SPDX-FileCopyrightText = "2026 Igalia S.L." +SPDX-License-Identifier = "MIT" [[annotations]] path = "src/moonforgecli/.gitignore" precedence = "aggregate" -SPDX-FileCopyrightText = "2026 Igalia S.L." +SPDX-FileCopyrightText = "2026 Igalia S.L." SPDX-License-Identifier = "CC0-1.0" diff --git a/src/moonforgecli/feature.py b/src/moonforgecli/feature.py index d27d4bf..47c7431 100644 --- a/src/moonforgecli/feature.py +++ b/src/moonforgecli/feature.py @@ -1,10 +1,6 @@ # SPDX-FileCopyrightText: 2026 Igalia S.L. # SPDX-License-Identifier: MIT -import argparse -import os -import sys - from . import log, term from .features import available_features, get_feature @@ -41,11 +37,11 @@ def run(options) -> int: features = [] for feat in options.features: - f = get_feature(feat) - if f is None: - log.error(f"Invalid feature {feat}.") + try: + f = get_feature(feat) + except IndexError as err: + log.error(f"{err}") features.append(f) - for feature in features: res = [] res.append(f"{term.heading('Feature:')} {term.bold(feature.name)}") @@ -64,7 +60,7 @@ def run(options) -> int: for include in feature.includes: res.append(f" - {term.green(include.file)} from {term.green(include.repo)}") res.append("") - if len(feature.conflicts) > 0: + if feature.conflicts is not None and len(feature.conflicts) > 0: res.append(term.heading("Conflicts:")) for conflict in feature.conflicts: res.append(f" - {term.red(conflict)}") diff --git a/src/moonforgecli/features/__init__.py b/src/moonforgecli/features/__init__.py index e9dece6..0a3c035 100644 --- a/src/moonforgecli/features/__init__.py +++ b/src/moonforgecli/features/__init__.py @@ -7,6 +7,7 @@ @dataclass class FeatureFragment: """Class for weighted template fragments.""" + section: str key: str value: str @@ -44,6 +45,7 @@ class FeatureRepo: @dataclass class Feature: """Class for feature templates.""" + name: str description: str includes: list[FeatureInclude] = field(default_factory=list) @@ -53,12 +55,13 @@ class Feature: variables: list[FeatureVariable] | None = field(default_factory=list) -def available_features() -> list[Features]: +def available_features() -> list[Feature]: from .docker import DOCKER_FEATURE from .graphics_weston import GRAPHICS_WESTON_FEATURE from .graphics_wpe import GRAPHICS_WPE_FEATURE from .podman import PODMAN_FEATURE from .rauc_simple import RAUC_FEATURE + return [ DOCKER_FEATURE, GRAPHICS_WESTON_FEATURE, @@ -68,22 +71,30 @@ def available_features() -> list[Features]: ] -def get_feature(name: str) -> Feature | None: +def get_feature(name: str) -> Feature: for feature in available_features(): if feature.name == name: return feature - return None + raise IndexError(f"Feature {name} not found") -def check_conflicts(name: str, features: list[str]) -> list[str] | None: - feature = get_feature(name) +def check_conflicts(name: str, features: list[str]) -> list[str]: + try: + feature = get_feature(name) + except IndexError: + return [] + feature_conflicts = getattr(feature, "conflicts", []) if len(feature_conflicts) == 0: - return None + return [] res = [] for feat in features: - check = get_feature(feat) + try: + check = get_feature(feat) + except IndexError: + continue + if check.name in feature_conflicts: res.append(check.name) else: @@ -91,7 +102,4 @@ def check_conflicts(name: str, features: list[str]) -> list[str] | None: if feature.name in check_conflicts: res.append(check.name) - if len(res) == 0: - return None - return res diff --git a/src/moonforgecli/features/docker.py b/src/moonforgecli/features/docker.py index 4961ea5..02335ee 100644 --- a/src/moonforgecli/features/docker.py +++ b/src/moonforgecli/features/docker.py @@ -1,12 +1,14 @@ # SPDX-FileCopyrightText: 2026 Igalia S.L. # SPDX-License-Identifier: MIT -from . import Feature, FeatureFragment, FeatureInclude +from . import Feature, FeatureInclude -DOCKER_FEATURE = Feature(name="docker", - description="Container support using Docker", - includes=[ - FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-docker.yml") - ], - conflicts=["podman"]) +DOCKER_FEATURE = Feature( + name="docker", + description="Container support using Docker", + includes=[ + FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-docker.yml") + ], + conflicts=["podman"], +) diff --git a/src/moonforgecli/features/graphics_weston.py b/src/moonforgecli/features/graphics_weston.py index 0f33408..1959f23 100644 --- a/src/moonforgecli/features/graphics_weston.py +++ b/src/moonforgecli/features/graphics_weston.py @@ -1,12 +1,16 @@ # SPDX-FileCopyrightText: 2026 Igalia S.L. # SPDX-License-Identifier: MIT -from . import Feature, FeatureFragment, FeatureInclude +from . import Feature, FeatureInclude -GRAPHICS_WESTON_FEATURE = Feature(name="graphics-weston", - description="Graphics support, using Weston", - includes=[ - FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-graphics.yml") - ], - conflicts=['graphics-wpe']) +GRAPHICS_WESTON_FEATURE = Feature( + name="graphics-weston", + description="Graphics support, using Weston", + includes=[ + FeatureInclude( + "meta-moonforge", "kas/include/layer/meta-moonforge-graphics.yml" + ) + ], + conflicts=["graphics-wpe"], +) diff --git a/src/moonforgecli/features/graphics_wpe.py b/src/moonforgecli/features/graphics_wpe.py index cb93d6d..edb6712 100644 --- a/src/moonforgecli/features/graphics_wpe.py +++ b/src/moonforgecli/features/graphics_wpe.py @@ -4,21 +4,29 @@ from . import Feature, FeatureFragment, FeatureInclude, FeatureVariable -GRAPHICS_WPE_FEATURE = Feature(name="graphics-wpe", - description="Web Platform for Embedded", - includes=[ - FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-graphics.yml"), - FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-wpe.yml"), - ], - local_conf=[ - FeatureFragment(section="meta-moonforge-wpe", - weight=30, - key="WAYLAND_COG_LAUNCH_URL", - value="http://10.0.2.2:8080"), - ], - conflicts=['graphics-weston'], - variables=[ - FeatureVariable(name="WAYLAND_COG_LAUNCH_URL", - description="The URL to display at boot", - default="http://10.0.2.2:8080"), - ]) +GRAPHICS_WPE_FEATURE = Feature( + name="graphics-wpe", + description="Web Platform for Embedded", + includes=[ + FeatureInclude( + "meta-moonforge", "kas/include/layer/meta-moonforge-graphics.yml" + ), + FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-wpe.yml"), + ], + local_conf=[ + FeatureFragment( + section="meta-moonforge-wpe", + weight=30, + key="WAYLAND_COG_LAUNCH_URL", + value="http://10.0.2.2:8080", + ), + ], + conflicts=["graphics-weston"], + variables=[ + FeatureVariable( + name="WAYLAND_COG_LAUNCH_URL", + description="The URL to display at boot", + default="http://10.0.2.2:8080", + ), + ], +) diff --git a/src/moonforgecli/features/podman.py b/src/moonforgecli/features/podman.py index a8544e7..c1b033b 100644 --- a/src/moonforgecli/features/podman.py +++ b/src/moonforgecli/features/podman.py @@ -1,12 +1,14 @@ # SPDX-FileCopyrightText: 2026 Igalia S.L. # SPDX-License-Identifier: MIT -from . import Feature, FeatureFragment, FeatureInclude +from . import Feature, FeatureInclude -PODMAN_FEATURE = Feature(name="podman", - description="Container support using Podman", - includes=[ - FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-podman.yml") - ], - conflicts=["docker"]) +PODMAN_FEATURE = Feature( + name="podman", + description="Container support using Podman", + includes=[ + FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-podman.yml") + ], + conflicts=["docker"], +) diff --git a/src/moonforgecli/features/rauc_simple.py b/src/moonforgecli/features/rauc_simple.py index 68ec9c7..8fc5831 100644 --- a/src/moonforgecli/features/rauc_simple.py +++ b/src/moonforgecli/features/rauc_simple.py @@ -4,51 +4,72 @@ from . import Feature, FeatureFragment, FeatureInclude, FeatureVariable -RAUC_FEATURE = Feature(name="rauc-simple", - description="RAUC support with update bundles via update script", - includes=[ - FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-rauc-update.yml"), - ], - local_conf=[ - FeatureFragment(section="meta-moonforge-rauc-update", - weight=40, - key="RAUC_BUNDLE_URL", - value="http://10.0.2.2:3333/LATEST.raucb"), - FeatureFragment(section="meta-moonforge-rauc-update", - weight=40, - key="RAUC_FORCE_REBOOT_ON_UPDATE", - value="1"), - ], - machine_overrides={ - "local_conf": { - "qemux86-64": [ - FeatureFragment(section="meta-moonforge-rauc-qemu", - weight=40, - key="WKS_FILE", - value="moonforge-image-rauc-qemux86-64.wks.in"), - ], - "raspberrypi5": [ - FeatureFragment(section="meta-moonforge-rauc-raspberry", - weight=40, - key="WKS_FILE", - value="moonforge-image-rauc-raspberrypi.wks.in"), - FeatureFragment(section="meta-moonforge-distro", - weight=20, - key="OVERLAYFS_ETC_DEVICE", - value="/dev/mmcblk0p4"), - ], - }, - "includes": { - "qemux86-64": [ - FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-rauc-qemu.yml"), - ], - "raspberrypi5": [ - FeatureInclude("meta-moonforge", "kas/include/layer/meta-moonforge-rauc-raspberrypi.yml"), - ], - }, - }, - variables=[ - FeatureVariable(name="RAUC_FORCE_REBOOT_ON_UPDATE", - description="Reboot on update", - default="1"), - ]) +RAUC_FEATURE = Feature( + name="rauc-simple", + description="RAUC support with update bundles via update script", + includes=[ + FeatureInclude( + "meta-moonforge", "kas/include/layer/meta-moonforge-rauc-update.yml" + ), + ], + local_conf=[ + FeatureFragment( + section="meta-moonforge-rauc-update", + weight=40, + key="RAUC_BUNDLE_URL", + value="http://10.0.2.2:3333/LATEST.raucb", + ), + FeatureFragment( + section="meta-moonforge-rauc-update", + weight=40, + key="RAUC_FORCE_REBOOT_ON_UPDATE", + value="1", + ), + ], + machine_overrides={ + "local_conf": { + "qemux86-64": [ + FeatureFragment( + section="meta-moonforge-rauc-qemu", + weight=40, + key="WKS_FILE", + value="moonforge-image-rauc-qemux86-64.wks.in", + ), + ], + "raspberrypi5": [ + FeatureFragment( + section="meta-moonforge-rauc-raspberry", + weight=40, + key="WKS_FILE", + value="moonforge-image-rauc-raspberrypi.wks.in", + ), + FeatureFragment( + section="meta-moonforge-distro", + weight=20, + key="OVERLAYFS_ETC_DEVICE", + value="/dev/mmcblk0p4", + ), + ], + }, + "includes": { + "qemux86-64": [ + FeatureInclude( + "meta-moonforge", "kas/include/layer/meta-moonforge-rauc-qemu.yml" + ), + ], + "raspberrypi5": [ + FeatureInclude( + "meta-moonforge", + "kas/include/layer/meta-moonforge-rauc-raspberrypi.yml", + ), + ], + }, + }, + variables=[ + FeatureVariable( + name="RAUC_FORCE_REBOOT_ON_UPDATE", + description="Reboot on update", + default="1", + ), + ], +) diff --git a/src/moonforgecli/init.py b/src/moonforgecli/init.py index 0ce4de9..ca2301b 100644 --- a/src/moonforgecli/init.py +++ b/src/moonforgecli/init.py @@ -1,15 +1,14 @@ # SPDX-FileCopyrightText: 2026 Igalia S.L. # SPDX-License-Identifier: MIT -import argparse import os import subprocess from pathlib import Path -from . import log, kas, utils -from .features import check_conflicts, get_feature -from .machines import get_machine +from . import log, kas, term, utils +from .features import Feature, check_conflicts, get_feature +from .machines import Machine, get_machine HELP_MSG = "Initialize a Moonforge project" @@ -95,7 +94,7 @@ def sanitize_project_name(name: str) -> str: class Project: - def __init__(self, name: str, path: Path, machine: Machine, features: list[Feature], variables: dict[str], vcs: str): + def __init__(self, name: str, path: Path, machine: Machine, features: list[Feature], variables: dict[str, str], vcs: str) -> None: self._name = name self._path = path self._machine = machine @@ -184,7 +183,6 @@ def add_conf_dir(project: Project) -> None: def add_kas_dir(project: Project) -> None: project_name = sanitize_project_name(project.name) - layer_name = sanitize_layer_name(project.name) kas_path = project.path / "kas" os.makedirs(kas_path, exist_ok=True) @@ -224,7 +222,7 @@ def init_vcs(project: Project) -> None: stderr=subprocess.PIPE) output, err = proc.communicate() if proc.returncode: - log.warning(f"Unable to initialize VCS: {err}") + log.warning(f"Unable to initialize VCS: {err!r}") return except Exception as e: log.warning(f"Unable to initialize VCS: {e}") @@ -263,17 +261,20 @@ def run(options): path = Path(project_path) if path.exists() and not path.is_dir(): log.error(f"Project path {path} exists and is not a directory.") - machine = get_machine(options.machine) - if machine is None: + try: + machine = get_machine(options.machine) + except IndexError: log.error(f"Invalid target machine {options.machine}. " - "Use 'list-machines' to list the available machines.") + f"Use {term.command('machine')} to list the available machines.") features = [] for feat in options.features: - f = get_feature(feat) - if f is None: - log.error(f"Invalid feature {feat}.") + try: + f = get_feature(feat) + except IndexError: + log.error(f"Invalid feature {feat}. " + f"Use {term.command('feature')} to list the available features.") conflicts = check_conflicts(feat, options.features) - if conflicts is not None: + if len(conflicts) > 0: res = ", ".join(conflicts) log.error(f"Feature {feat} conflicts with the following features: {res}") features.append(f) diff --git a/src/moonforgecli/kas.py b/src/moonforgecli/kas.py index 7e81857..750343f 100644 --- a/src/moonforgecli/kas.py +++ b/src/moonforgecli/kas.py @@ -3,8 +3,8 @@ from dataclasses import dataclass, field -from .features import FeatureFragment, Feature -from .machines import MachineFragment, Machine +from .features import Feature +from .machines import Machine from . import log @@ -12,7 +12,7 @@ @dataclass class KasInclude: """Class for kas include directives.""" - repo: str + repo: str | None file: str @@ -26,7 +26,8 @@ class KasHeader: @dataclass class KasFragment: section: str - text: list[str] + key: str + value: str weight: int = 0 @@ -37,25 +38,24 @@ class KasRepo: url: str | None = None commit: str | None = None branch: str | None = None - layers: list[str] = field(default_factory=list) + layers: list[str] | None = None class KasFile: """Class for kas files.""" - def __init__(self): + def __init__(self) -> None: self._header: KasHeader = KasHeader() self._repos: list[KasRepo] = [] self._distro: str | None = None self._machine: Machine | None = None - self._features: list[Feature] | None = [] - self._variables: dict[str, str] | None = {} + self._features: list[Feature] = [] + self._variables: dict[str, str] = {} self._local_conf: list[KasFragment] = [] - self._wks: list[KasFragment] = [] def add_include(self, repo: str | None, file: str) -> None: self._header.includes.append(KasInclude(repo, file)) - def add_repo(self, name: str, url: str, commit: str | None = None, branch: str = None) -> None: + def add_repo(self, name: str, url: str, commit: str | None = None, branch: str | None = None) -> None: for r in self._repos: if r.name == name: log.debug(f"Repository {r.name} (url: {r.url}) already exists") @@ -148,7 +148,7 @@ def _build_repos(self) -> list[str]: output.append(f" commit: {r.commit}") if r.branch is not None: output.append(f" branch: {r.branch}") - if len(r.layers) > 0: + if r.layers is not None and len(r.layers) > 0: output.append(" layers:") for layer in r.layers: output.append(f" {layer}:") @@ -185,10 +185,9 @@ def _build_local_conf(self) -> list[str]: effective_fragments = sorted(seen_keys.values(), key=lambda frag: frag.weight) # Split fragments into sections - sections = {} + sections: dict[str, list[KasFragment]] = {} for frag in effective_fragments: - section = sections.setdefault(f"{frag.weight}_{frag.section}", []) - section.append(frag) + sections.setdefault(f"{frag.weight}_{frag.section}", []).append(frag) output = [] if len(sections) > 0: diff --git a/src/moonforgecli/log.py b/src/moonforgecli/log.py index 4d01c0c..6386f2d 100644 --- a/src/moonforgecli/log.py +++ b/src/moonforgecli/log.py @@ -2,7 +2,6 @@ # SPDX-License-Identifier: MIT import os -import platform import sys import time import threading diff --git a/src/moonforgecli/machine.py b/src/moonforgecli/machine.py index e5d4be5..dde28dd 100644 --- a/src/moonforgecli/machine.py +++ b/src/moonforgecli/machine.py @@ -1,10 +1,6 @@ # SPDX-FileCopyrightText: 2026 Igalia S.L. # SPDX-License-Identifier: MIT -import argparse -import os -import sys - from . import log, term from .machines import available_machines, get_machine @@ -41,11 +37,11 @@ def run(options) -> int: machines = [] for machine in options.machines: - m = get_machine(machine) - if m is None: - log.error(f"Invalid machine {machine}.") + try: + m = get_machine(machine) + except IndexError as err: + log.error(f"{err}") machines.append(m) - for machine in machines: res = [] res.append(f"{term.heading('Machine:')} {term.bold(machine.name)}") diff --git a/src/moonforgecli/machines/__init__.py b/src/moonforgecli/machines/__init__.py index 6cf2b84..983910d 100644 --- a/src/moonforgecli/machines/__init__.py +++ b/src/moonforgecli/machines/__init__.py @@ -7,6 +7,7 @@ @dataclass class MachineFragment: """Class for weighted template fragments.""" + section: str key: str value: str @@ -31,6 +32,7 @@ class MachineRepo: @dataclass class Machine: """Class for machine templates.""" + name: str description: str includes: list[MachineInclude] = field(default_factory=list) @@ -49,10 +51,10 @@ def available_machines() -> list[Machine]: ] -def get_machine(name: str) -> Machine | None: +def get_machine(name: str) -> Machine: for machine in available_machines(): if name == "default" and machine.default: return machine if machine.name == name: return machine - return None + raise IndexError(f"Machine {name} not found") diff --git a/src/moonforgecli/machines/qemu.py b/src/moonforgecli/machines/qemu.py index 81e7fc4..e289f81 100644 --- a/src/moonforgecli/machines/qemu.py +++ b/src/moonforgecli/machines/qemu.py @@ -4,23 +4,31 @@ from . import Machine, MachineFragment, MachineInclude -QEMU_MACHINE = Machine(name="qemux86-64", - description="QEMU x86_64 builds", - includes=[ - MachineInclude("meta-moonforge", "kas/include/layer/meta-moonforge-qemu.yml") - ], - local_conf=[ - MachineFragment(section="meta-moonforge-distro", - weight=20, - key="OVERLAYFS_ETC_DEVICE", - value="/dev/sda4"), - MachineFragment(section="meta-moonforge-distro", - weight=20, - key="IMAGE_DATA_MIN_SIZE", - value="4096M"), - MachineFragment(section="meta-moonforge-qemu", - weight=20, - key="WKS_FILE", - value="moonforge-image-base-qemux86-64.wks.in"), - ], - default=True) +QEMU_MACHINE = Machine( + name="qemux86-64", + description="QEMU x86_64 builds", + includes=[ + MachineInclude("meta-moonforge", "kas/include/layer/meta-moonforge-qemu.yml") + ], + local_conf=[ + MachineFragment( + section="meta-moonforge-distro", + weight=20, + key="OVERLAYFS_ETC_DEVICE", + value="/dev/sda4", + ), + MachineFragment( + section="meta-moonforge-distro", + weight=20, + key="IMAGE_DATA_MIN_SIZE", + value="4096M", + ), + MachineFragment( + section="meta-moonforge-qemu", + weight=20, + key="WKS_FILE", + value="moonforge-image-base-qemux86-64.wks.in", + ), + ], + default=True, +) diff --git a/src/moonforgecli/machines/raspberrypi5.py b/src/moonforgecli/machines/raspberrypi5.py index 64dac42..72b752a 100644 --- a/src/moonforgecli/machines/raspberrypi5.py +++ b/src/moonforgecli/machines/raspberrypi5.py @@ -4,22 +4,32 @@ from . import Machine, MachineFragment, MachineInclude -RPI5_MACHINE = Machine(name="raspberrypi5", - description="RaspberryPi 5 builds", - includes=[ - MachineInclude("meta-moonforge", "kas/include/layer/meta-moonforge-raspberrypi.yml"), - ], - local_conf=[ - MachineFragment(section="meta-moonforge-raspberrypi", - weight=20, - key="WKS_FILE", - value="moonforge-image-base-raspberrypi.wks.in"), - MachineFragment(section="meta-moonforge-distro", - weight=20, - key="OVERLAYFS_ETC_DEVICE", - value="/dev/mmcblk0p3"), - MachineFragment(section="meta-moonforge-distro", - weight=20, - key="IMAGE_DATA_MIN_SIZE", - value="4096M"), - ]) +RPI5_MACHINE = Machine( + name="raspberrypi5", + description="RaspberryPi 5 builds", + includes=[ + MachineInclude( + "meta-moonforge", "kas/include/layer/meta-moonforge-raspberrypi.yml" + ), + ], + local_conf=[ + MachineFragment( + section="meta-moonforge-raspberrypi", + weight=20, + key="WKS_FILE", + value="moonforge-image-base-raspberrypi.wks.in", + ), + MachineFragment( + section="meta-moonforge-distro", + weight=20, + key="OVERLAYFS_ETC_DEVICE", + value="/dev/mmcblk0p3", + ), + MachineFragment( + section="meta-moonforge-distro", + weight=20, + key="IMAGE_DATA_MIN_SIZE", + value="4096M", + ), + ], +) diff --git a/src/moonforgecli/term.py b/src/moonforgecli/term.py index 94bcf67..242a39d 100644 --- a/src/moonforgecli/term.py +++ b/src/moonforgecli/term.py @@ -4,8 +4,11 @@ import os import sys +from enum import Enum -class TermColor: + +class TermColor(Enum): + """Type of color support inside the terminal.""" NONE = 0 EXT = 1 TRUE = 2 @@ -67,7 +70,6 @@ class AnsiEscape(object): WHITE_BG = 47 DEFAULT_BG = 49 - def __init__(self, *args, **kwargs): self._text = kwargs.get('text', '') self._mods = kwargs.get('mods', AnsiEscape.NONE) @@ -155,7 +157,7 @@ def __str__(self): return f"{self.pre}{self.text}{self.post}" -def red(text) ->str: +def red(text) -> str: return AnsiEscape(text=text).color(fg=AnsiEscape.RED_FG) diff --git a/src/moonforgecli/utils.py b/src/moonforgecli/utils.py index 5988c9b..8624eb6 100644 --- a/src/moonforgecli/utils.py +++ b/src/moonforgecli/utils.py @@ -2,12 +2,11 @@ # SPDX-License-Identifier: MIT import os -import sys from . import log -FOUND_PROGRAMS = {} +FOUND_PROGRAMS: dict[str, str] = {} def find_program(bin_name: str, path: str | None = None, error_if_not_found: bool = False) -> str | None: