diff --git a/devices/device.py b/devices/device.py index b53adbb..ce83d01 100644 --- a/devices/device.py +++ b/devices/device.py @@ -11,7 +11,7 @@ from distro.package import LocalPackage from packages.pkgbuild import Pkgbuild, _pkgbuilds_cache, discover_pkgbuilds, get_pkgbuild_by_path, init_pkgbuilds from utils import read_files_from_tar, color_str -from .deviceinfo import DeviceInfo, parse_deviceinfo +from .deviceinfo import DEFAULT_IMAGE_SECTOR_SIZE, DeviceInfo, parse_deviceinfo DEVICE_DEPRECATIONS = { "oneplus-enchilada": "sdm845-oneplus-enchilada", @@ -69,7 +69,7 @@ class Device(DictScheme): result["package_path"] = self.package.path if self.package else None return DeviceSummary(result) - def parse_deviceinfo(self, try_download: bool = True, lazy: bool = True): + def parse_deviceinfo(self, try_download: bool = True, lazy: bool = True) -> DeviceInfo: if not lazy or 'deviceinfo' not in self or self.deviceinfo is None: # avoid import loop from packages.build import check_package_version_built @@ -96,8 +96,16 @@ class Device(DictScheme): assert info.arch assert info.arch == self.arch self['deviceinfo'] = info + assert self.deviceinfo return self.deviceinfo + def get_image_sectorsize(self, **kwargs) -> Optional[int]: + """Gets the deviceinfo_rootfs_image_sector_size if defined, otherwise None""" + return self.parse_deviceinfo(**kwargs).get('rootfs_image_sector_size', None) + + def get_image_sectorsize_default(self, **kwargs) -> int: + return self.get_image_sectorsize(**kwargs) or DEFAULT_IMAGE_SECTOR_SIZE + def check_devicepkg_name(name: str, log_level: Optional[int] = None): valid = True diff --git a/devices/deviceinfo.py b/devices/deviceinfo.py index b9acf3a..2a86bf2 100644 --- a/devices/deviceinfo.py +++ b/devices/deviceinfo.py @@ -5,7 +5,7 @@ import copy import logging import os -from typing import Any, Mapping, Optional +from typing import Mapping, Optional from config.state import config from constants import Arch @@ -15,6 +15,8 @@ PMOS_ARCHES_OVERRIDES: dict[str, Arch] = { "armv7": 'armv7h', } +DEFAULT_IMAGE_SECTOR_SIZE = 512 + class DeviceInfo(DictScheme): arch: Arch @@ -24,10 +26,12 @@ class DeviceInfo(DictScheme): chassis: str flash_pagesize: int flash_method: str + rootfs_image_sector_size: Optional[int] @classmethod - def transform(cls, values: Mapping[str, str], validate: bool = True, allow_extra: bool = True, type_hints: Optional[dict[str, Any]] = None): - return super().transform(values, validate=validate, allow_extra=allow_extra) + def transform(cls, values: Mapping[str, Optional[str]], **kwargs): + kwargs = {'allow_extra': True} | kwargs + return super().transform(values, **kwargs) # Variables from deviceinfo. Reference: @@ -115,7 +119,7 @@ deviceinfo_chassis_types = [ ] -def sanity_check(deviceinfo: dict[str, str], device_name: str): +def sanity_check(deviceinfo: dict[str, Optional[str]], device_name: str): try: _pmos_sanity_check(deviceinfo, device_name) except RuntimeError as err: @@ -129,7 +133,7 @@ def sanity_check(deviceinfo: dict[str, str], device_name: str): f"{err}") -def _pmos_sanity_check(info: dict[str, str], device_name: str): +def _pmos_sanity_check(info: dict[str, Optional[str]], device_name: str): # Resolve path for more readable error messages path = os.path.join(config.get_path('pkgbuilds'), 'device', device_name, 'deviceinfo') @@ -194,7 +198,7 @@ def _pmos_sanity_check(info: dict[str, str], device_name: str): f" and try again: {path}") -def parse_kernel_suffix(deviceinfo: dict[str, str], kernel: str = 'mainline') -> dict[str, str]: +def parse_kernel_suffix(deviceinfo: dict[str, Optional[str]], kernel: str = 'mainline') -> dict[str, Optional[str]]: """ Remove the kernel suffix (as selected in 'pmbootstrap init') from deviceinfo variables. Related: @@ -240,7 +244,7 @@ def parse_deviceinfo(deviceinfo_lines: list[str], device_name: str, kernel='main :param device: defaults to args.device :param kernel: defaults to args.kernel """ - info = {} + info: dict[str, Optional[str]] = {} for line in deviceinfo_lines: line = line.strip() if line.startswith("#") or not line: @@ -258,12 +262,12 @@ def parse_deviceinfo(deviceinfo_lines: list[str], device_name: str, kernel='main # Assign empty string as default for key in deviceinfo_attributes: if key not in info: - info[key] = "" + info[key] = None info = parse_kernel_suffix(info, kernel) sanity_check(info, device_name) if 'arch' in info: arch = info['arch'] - info['arch'] = PMOS_ARCHES_OVERRIDES.get(arch, arch) + info['arch'] = PMOS_ARCHES_OVERRIDES.get(arch, arch) # type: ignore[arg-type] dev = DeviceInfo.fromDict(info) return dev diff --git a/dictscheme.py b/dictscheme.py index 25578bb..c5537d3 100644 --- a/dictscheme.py +++ b/dictscheme.py @@ -58,6 +58,7 @@ class DictScheme(Munch): def transform( cls, values: Mapping[str, Any], + *, validate: bool = True, allow_extra: bool = False, type_hints: Optional[dict[str, Any]] = None, @@ -251,7 +252,7 @@ class DictScheme(Munch): return result def update(self, d: Mapping[str, Any], validate: bool = True): - Munch.update(self, type(self).transform(d, validate)) + Munch.update(self, type(self).transform(d, validate=validate)) def __init_subclass__(cls): super().__init_subclass__() diff --git a/image/flash.py b/image/flash.py index da8c9ad..40b6ef8 100644 --- a/image/flash.py +++ b/image/flash.py @@ -85,10 +85,8 @@ def cmd_flash( device_image_path = get_image_path(device, flavour) deviceinfo = device.parse_deviceinfo() - sector_size = sector_size or deviceinfo.flash_pagesize + sector_size = sector_size or device.get_image_sectorsize_default() method = method or deviceinfo.flash_method - if not sector_size: - raise Exception(f"Device {device.name} has no flash_pagesize specified") if what not in FLASH_PARTS.values(): raise Exception(f'Unknown what "{what}", must be one of {", ".join(FLASH_PARTS.values())}') diff --git a/image/image.py b/image/image.py index a6e73e9..d332ac1 100644 --- a/image/image.py +++ b/image/image.py @@ -274,30 +274,31 @@ def partition_device(device: str): raise Exception(f'Failed to create partitions on {device}') -def create_filesystem(device: str, blocksize: int = 4096, label=None, options=[], fstype='ext4'): - # blocksize can be 4k max due to pagesize - blocksize = min(blocksize, 4096) - if fstype.startswith('ext'): - # blocksize for ext-fs must be >=1024 - blocksize = max(blocksize, 1024) - +def create_filesystem(device: str, blocksize: Optional[int], label=None, options=[], fstype='ext4'): + """Creates a new filesystem. Blocksize defaults""" labels = ['-L', label] if label else [] - cmd = [ - f'mkfs.{fstype}', - '-F', - '-b', - str(blocksize), - ] + labels + [device] + cmd = [f'mkfs.{fstype}', '-F', *labels] + if blocksize: + # blocksize can be 4k max due to pagesize + blocksize = min(blocksize, 4096) + if fstype.startswith('ext'): + # blocksize for ext-fs must be >=1024 + blocksize = max(blocksize, 1024) + cmd += [ + '-b', + str(blocksize), + ] + cmd.append(device) result = run_root_cmd(cmd) if result.returncode != 0: raise Exception(f'Failed to create {fstype} filesystem on {device} with CMD: {cmd}') -def create_root_fs(device: str, blocksize: int): +def create_root_fs(device: str, blocksize: Optional[int]): create_filesystem(device, blocksize=blocksize, label='kupfer_root', options=['-O', '^metadata_csum', '-N', '100000']) -def create_boot_fs(device: str, blocksize: int): +def create_boot_fs(device: str, blocksize: Optional[int]): create_filesystem(device, blocksize=blocksize, label='kupfer_boot', fstype='ext2') @@ -447,10 +448,7 @@ def cmd_build( pkgbuilds |= set(filter_pkgbuilds(packages_extra, arch=arch, allow_empty_results=True, use_paths=False)) build_packages(pkgbuilds, arch, try_download=not no_download_pkgs) - deviceinfo = device.parse_deviceinfo() - sector_size = sector_size or deviceinfo.flash_pagesize - if not sector_size: - raise Exception(f"Device {device.name} has no flash_pagesize specified") + sector_size = sector_size or device.get_image_sectorsize() image_path = block_target or get_image_path(device, flavour.name) @@ -459,7 +457,7 @@ def cmd_build( logging.info(f'Creating new file at {image_path}') create_img_file(image_path, f"{rootfs_size_mb}M") - loop_device = losetup_rootfs_image(image_path, sector_size) + loop_device = losetup_rootfs_image(image_path, sector_size or device.get_image_sectorsize_default()) partition_device(loop_device) partprobe(loop_device) @@ -512,10 +510,7 @@ def cmd_inspect(profile: Optional[str] = None, shell: bool = False, sector_size: device = get_profile_device(profile) arch = device.arch flavour = get_profile_flavour(profile).name - deviceinfo = device.parse_deviceinfo() - sector_size = sector_size or deviceinfo.flash_pagesize - if not sector_size: - raise Exception(f"Device {device.name} has no flash_pagesize specified") + sector_size = sector_size or device.get_image_sectorsize_default() chroot = get_device_chroot(device.name, flavour, arch) image_path = get_image_path(device, flavour)