diff --git a/image/build-iso.sh b/image/build-iso.sh index 62266ce..880c1b4 100755 --- a/image/build-iso.sh +++ b/image/build-iso.sh @@ -216,20 +216,41 @@ import sys path, unattended, version = sys.argv[1], sys.argv[2] == "1", sys.argv[3] text = open(path).read() # /autoinstall.yaml applies to every entry, so all Ubuntu entries become Virtuality entries. -suffix = " (UNATTENDED: erases disk)" if unattended else "" -text = text.replace('menuentry "Try or Install Ubuntu Server"', 'menuentry "Install Virtuality %s%s"' % (version, suffix), 1) -text = text.replace('menuentry "Ubuntu Server with the HWE kernel"', 'menuentry "Install Virtuality %s with the HWE kernel%s"' % (version, suffix), 1) -if "Install Virtuality" not in text: +suffix = " — автоматически, диск будет стёрт" if unattended else "" +text = text.replace('menuentry "Try or Install Ubuntu Server"', 'menuentry "Установить Virtuality %s%s"' % (version, suffix), 1) +text = text.replace('menuentry "Ubuntu Server with the HWE kernel"', 'menuentry "Установить Virtuality %s (новое ядро HWE)%s"' % (version, suffix), 1) +text = text.replace("menuentry 'Boot from next volume'", "menuentry 'Загрузить с другого диска'", 1) +text = text.replace("menuentry 'UEFI Firmware Settings'", "menuentry 'Настройки UEFI'", 1) +text = text.replace("menuentry 'Test memory'", "menuentry 'Проверить память'", 1) +if "Установить Virtuality" not in text: raise SystemExit("unexpected grub.cfg menu titles") if unattended: text = re.sub(r"^(\s*linux\s+\S+\s+)---", r"\1autoinstall ---", text, flags=re.M) -text = re.sub(r"^set timeout=\d+", "set default=0\nset timeout=10", text, count=1, flags=re.M) -open(path, "w").write(text) +text = re.sub(r"^set timeout=\d+\n", "", text, count=1, flags=re.M) +text = text.replace("loadfont unicode\n", "", 1) +# Branded graphical menu; if a module or the font is missing GRUB falls back to the plain text menu. +theme = """insmod all_video +insmod gfxterm +insmod png +insmod gfxmenu +set gfxmode=1024x768,auto +if loadfont /boot/grub/fonts/unicode.pf2; then + terminal_output gfxterm + set theme=/boot/grub/themes/virtuality/theme.txt + export theme +fi +set default=0 +set timeout=10 +""" +open(path, "w").write(theme + text) PYEOF new_md5="$(md5sum "${WORK_DIR}/grub.cfg" | cut -d' ' -f1)" sed -i "s|^[0-9a-f]\{32\} \./boot/grub/grub.cfg$|${new_md5} ./boot/grub/grub.cfg|" "${WORK_DIR}/md5sum.txt" # ---------------------------------------------------------- repack +THEME_DIR="${WORK_DIR}/theme" +mkdir -p "$THEME_DIR" +cp "${IMAGE_DIR}"/grub/theme.txt "${IMAGE_DIR}"/grub/*.png "$THEME_DIR"/ say "Writing ${OUTPUT_ISO}" rm -f "$OUTPUT_ISO" chmod -R a+rX,go-w "$PAYLOAD" @@ -238,6 +259,7 @@ if ! xorriso -indev "$UBUNTU_ISO" -outdev "$OUTPUT_ISO" \ -map "$PAYLOAD" /virtuality \ -map "${WORK_DIR}/autoinstall.yaml" /autoinstall.yaml \ -map "${WORK_DIR}/grub.cfg" /boot/grub/grub.cfg \ + -map "${THEME_DIR}" /boot/grub/themes/virtuality \ -map "${WORK_DIR}/md5sum.txt" /md5sum.txt \ -boot_image any replay > "${WORK_DIR}/xorriso.log" 2>&1; then tail -n 30 "${WORK_DIR}/xorriso.log" >&2 diff --git a/image/grub/README.md b/image/grub/README.md new file mode 100644 index 0000000..78fbdc5 --- /dev/null +++ b/image/grub/README.md @@ -0,0 +1,12 @@ +# Тема загрузочного меню + +`theme.txt` — тема GRUB (gfxmenu) для установочного ISO, `background.png` — фон 1024×768, +`select_*.png` — подсветка выбранного пункта. + +Фон рендерится из `background.html` (тот же стиль, что у страницы входа панели): + +```bash +NODE_PATH=$(npm root -g) node tests/render_html.mjs image/grub/background.html image/grub/background.png 1024 768 +``` + +Пиксмапы подсветки — однотонные RGBA 6×6 (110, 96, 255, 150). diff --git a/image/grub/background.html b/image/grub/background.html new file mode 100644 index 0000000..8f8e246 --- /dev/null +++ b/image/grub/background.html @@ -0,0 +1,19 @@ +
+
VirtualityПлатформа виртуализации
+
Ваши серверы.
Под полным контролем.
+
Установщик · KVM · QEMU · libvirt
+
↑ ↓ — выбор пункта, Enter — запуск
+ diff --git a/image/grub/background.png b/image/grub/background.png new file mode 100644 index 0000000..87aa82e Binary files /dev/null and b/image/grub/background.png differ diff --git a/image/grub/select_c.png b/image/grub/select_c.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_c.png differ diff --git a/image/grub/select_e.png b/image/grub/select_e.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_e.png differ diff --git a/image/grub/select_n.png b/image/grub/select_n.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_n.png differ diff --git a/image/grub/select_ne.png b/image/grub/select_ne.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_ne.png differ diff --git a/image/grub/select_nw.png b/image/grub/select_nw.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_nw.png differ diff --git a/image/grub/select_s.png b/image/grub/select_s.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_s.png differ diff --git a/image/grub/select_se.png b/image/grub/select_se.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_se.png differ diff --git a/image/grub/select_sw.png b/image/grub/select_sw.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_sw.png differ diff --git a/image/grub/select_w.png b/image/grub/select_w.png new file mode 100644 index 0000000..5408fbd Binary files /dev/null and b/image/grub/select_w.png differ diff --git a/image/grub/theme.txt b/image/grub/theme.txt new file mode 100644 index 0000000..ca62627 --- /dev/null +++ b/image/grub/theme.txt @@ -0,0 +1,41 @@ +desktop-image: "background.png" +desktop-image-scale-method: "stretch" +desktop-color: "#0b0a1f" +title-text: "" +terminal-font: "Unicode Regular" +terminal-left: "7%" +terminal-top: "36%" +terminal-width: "86%" +terminal-height: "50%" +terminal-border: "0" + ++ boot_menu { + left = 7% + top = 36% + width = 60% + height = 42% + item_font = "Unicode Regular" + item_color = "#b9b8cf" + selected_item_color = "#ffffff" + item_height = 36 + item_padding = 10 + item_spacing = 6 + icon_width = 0 + icon_height = 0 + scrollbar = false + selected_item_pixmap_style = "select_*.png" +} + ++ progress_bar { + id = "__timeout__" + left = 7% + top = 86% + width = 60% + height = 24 + font = "Unicode Regular" + text_color = "#ffffff" + fg_color = "#7b6bff" + bg_color = "#1c1a36" + border_color = "#2a2748" + text = "Автоматический запуск через %d с" +} diff --git a/tests/render_html.mjs b/tests/render_html.mjs new file mode 100644 index 0000000..049dbac --- /dev/null +++ b/tests/render_html.mjs @@ -0,0 +1,10 @@ +import { createRequire } from 'node:module'; +const { chromium } = createRequire(import.meta.url)('playwright'); +// Render an HTML file to PNG. Usage: node tests/render_html.mjs in.html out.png [width] [height] +const [,, html, out, width = '1024', height = '768'] = process.argv; +const browser = await chromium.launch(); +const page = await browser.newPage({ viewport: { width: +width, height: +height }, deviceScaleFactor: 1 }); +await page.goto('file://' + (html.startsWith('/') ? html : process.cwd() + '/' + html)); +await page.waitForTimeout(300); +await page.screenshot({ path: out, type: 'png' }); +await browser.close();