Coverage for jumpstarter_driver_flashers/bundle.py: 93%
83 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-30 18:45 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-30 18:45 +0200
1import os
2from typing import Literal
4import yaml
5from pydantic import BaseModel, Field
8class FileAddress(BaseModel):
9 file: str
10 address: str
12class DtbVariant(BaseModel):
13 bootcmd: None | str = None
14 file: None | str = None
16class Dtb(BaseModel):
17 default: str
18 address: str
19 variants: dict[str, DtbVariant]
21class FlasherLogin(BaseModel):
22 login_prompt: str
23 username: str | None = None
24 password: str | None = None
25 prompt: str
28class FlashBundleSpecV1Alpha1(BaseModel):
29 manufacturer: str
30 link: None | str
31 bootcmd: str
32 shelltype: Literal["busybox"] = Field(default="busybox")
33 login: FlasherLogin = Field(default_factory=lambda: FlasherLogin(login_prompt="login:", prompt="#"))
34 default_target: str
35 targets: dict[str, str]
36 kernel: FileAddress
37 initram: None | FileAddress = None
38 dtb: None | Dtb = None
39 preflash_commands: list[str] = Field(default_factory=list)
42class ObjectMeta(BaseModel):
43 name: str
46class FlasherBundleManifestV1Alpha1(BaseModel):
47 apiVersion: Literal["jumpstarter.dev/v1alpha1"] = Field(default="jumpstarter.dev/v1alpha1")
48 kind: Literal["FlashBundleManifest"] = Field(default="FlashBundleManifest")
49 metadata: ObjectMeta
50 spec: FlashBundleSpecV1Alpha1
52 def get_dtb_address(self) -> str | None:
53 if not self.spec.dtb:
54 return None
55 return self.spec.dtb.address
57 def get_dtb_file(self, variant: str | None = None) -> str | None:
58 if not self.spec.dtb:
59 return None
61 # if no variant is provided, use the default variant name from the manifest
62 if not variant:
63 variant = self.spec.dtb.default
65 # look for the variant struct in this manifest
66 variant_struct = self.spec.dtb.variants.get(variant)
67 if variant_struct:
68 return variant_struct.file
69 else:
70 raise ValueError(f"DTB variant {variant} not found in the manifest.")
72 def get_boot_cmd(self, variant: str | None = None) -> str:
73 if not self.spec.dtb:
74 return self.spec.bootcmd
75 # if no variant is provided, use the default variant name from the manifest
76 if not variant:
77 variant = self.spec.dtb.default
78 # look for the variant struct in this manifest
79 variant_struct = self.spec.dtb.variants.get(variant)
80 if variant_struct:
81 # If variant has a custom bootcmd, use it; otherwise fall back to default
82 if variant_struct.bootcmd:
83 return variant_struct.bootcmd
84 else:
85 return self.spec.bootcmd
86 else:
87 raise ValueError(f"DTB variant {variant} not found in the manifest.")
89 def get_kernel_address(self) -> str:
90 return self.spec.kernel.address
92 def get_kernel_file(self) -> str:
93 return self.spec.kernel.file
95 def get_initram_file(self) -> str | None:
96 if not self.spec.initram:
97 return None
98 return self.spec.initram.file
100 def get_initram_address(self) -> str | None:
101 if not self.spec.initram:
102 return None
103 return self.spec.initram.address
105 @classmethod
106 def from_file(cls, path: os.PathLike):
107 with open(path) as f:
108 v = cls.model_validate(yaml.safe_load(f))
109 return v
111 @classmethod
112 def from_string(cls, data: str):
113 v = cls.model_validate(yaml.safe_load(data))
114 return v