-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathultra.py
150 lines (115 loc) · 4.17 KB
/
ultra.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from . import generator as g, uefi
from typing import Optional, List
import tempfile
import subprocess
import os
import shutil
def _optimal_fs_size_mb(fs_type):
if fs_type == "FAT12":
return 3
if fs_type == "FAT16":
return 32
if fs_type == "FAT32":
return 64
raise RuntimeError(f"Unknown filesystem type {fs_type}")
class Module:
format_string = \
"""
module:
name = "{name}"
type = "{type}"
path = "{path}"
size = "{size}"
"""
def __init__(
self, name: str, is_file: bool,
path: Optional[str] = None, size: Optional[int] = None
):
self.name = name
self.is_file = is_file
self.path = path
self.size = size
def __str__(self) -> str:
if self.name == "__KERNEL__":
return "kernel-as-module = true"
module_type = "file" if self.is_file else "memory"
path = self.path or ""
size = self.size or "auto"
return Module.format_string.format(
name=self.name, type=module_type, path=path, size=size
)
class DiskImage:
# always align partitions at 1 MiB
part_align_mibs = 1
def __init__(
self, fs_root_dir: str, br_type: str,
fs_type: str, fs_size_mb: Optional[int] = None,
hyper_config: Optional[str] = None,
hyper_uefi_binary_paths: List[str] = [],
hyper_iso_br_path: Optional[str] = None,
hyper_installer_path: Optional[str] = None,
out_path: Optional[str] = None,
cleanup: bool = True,
):
self.__fs_root_dir = fs_root_dir
self.__br_type = br_type.upper()
self.__fs_type = fs_type.upper()
self.__path = out_path if out_path else tempfile.mkstemp()[1]
self.__should_cleanup = cleanup
if hyper_config is not None:
with open(os.path.join(fs_root_dir, "hyper.cfg"), "w") as f:
f.write(hyper_config)
is_iso = self.fs_type == "ISO9660"
if not is_iso:
if fs_size_mb is None:
fs_size_mb = _optimal_fs_size_mb(self.fs_type)
image_size = fs_size_mb + DiskImage.part_align_mibs
# Make sure the backup header is intact
if br_type == "GPT":
image_size += 1
g.file_resize_to_mib(self.__path, image_size)
if self.__br_type == "MBR" or self.__br_type == "GPT":
g.image_partition(self.__path, self.__br_type, self.__fs_type,
DiskImage.part_align_mibs, fs_size_mb)
uefi_root_path = None
if hyper_uefi_binary_paths:
uefi_root_path = tempfile.TemporaryDirectory()
efi_boot_path = os.path.join(uefi_root_path.name, "EFI/BOOT")
os.makedirs(efi_boot_path)
for binary in hyper_uefi_binary_paths:
out_path = os.path.join(
efi_boot_path,
uefi.guess_canonical_file_name_for_binary(binary)
)
shutil.copy(binary, out_path)
g.make_fs(self.__path, self.__fs_type, DiskImage.part_align_mibs,
fs_size_mb, self.__fs_root_dir,
uefi_root_path.name if uefi_root_path else None,
hyper_iso_br_path)
if uefi_root_path is not None:
uefi_root_path.cleanup()
should_install = False
if hyper_installer_path is not None and self.__br_type != "GPT":
should_install = True
# Hybrid boot depends on having stage2 pointed to by el-torito
if is_iso:
should_install = should_install and hyper_iso_br_path is not None
if should_install:
assert hyper_installer_path
subprocess.check_call([hyper_installer_path, self.__path])
@property
def br_type(self):
return self.__br_type
def is_cd(self):
return self.__br_type == "CD"
@property
def fs_type(self):
return self.__fs_type
@property
def path(self):
return self.__path
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if self.__should_cleanup:
os.remove(self.__path)