* [PATCH 0/4] installer: separate installer into backend, UI, and flow modules
@ 2026-04-27 6:39 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 1/4] installer: extract backend helpers to sys_api.sh 'Kasturi shekar' via isar-users
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: 'Kasturi shekar' via isar-users @ 2026-04-27 6:39 UTC (permalink / raw)
To: isar-users; +Cc: kasturi.shekar
From: "kasturi.shekar" <kasturi.shekar@siemens.com>
This series refactors the installer by separating backend logic,
attended UI, and high-level flow into dedicated modules.
The main objectives are:
- improve readability and maintainability
- keep behavior and user-visible flow unchanged
Patch-1: introduces a backend API layer (sys_api.sh) that provides
installer functionality via structured shell functions.
Patch-2: adapts the existing dialog-based installer frontend to consume
these APIs, without changing behavior.
Patch-3: high-level orchestration and keep deploy-image-wic.sh as a thin launcher.
This keeps the externally used script name stable while making the flow easier
to review and maintain.
patch-4: update deploy-image recipe to ship the newly split installer modules
kasturi.shekar (4):
installer: extract backend helpers to sys_api.sh
installer: extract attended UI to installer_ui.sh
installer: add installer flow module and entrypoint
installer: install seprated installer modules in recipe
.../deploy-image/deploy-image_0.1.bb | 6 +-
.../files/usr/bin/deploy-image-wic.sh | 475 +++++++-----------
.../files/usr/bin/installer_ui.sh | 217 +++++---
.../deploy-image/files/usr/bin/sys_api.sh | 397 ++++++++++++---
4 files changed, 688 insertions(+), 407 deletions(-)
mode change 100755 => 100644 meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh
mode change 100755 => 100644 meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh
--
2.47.3
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260427063957.603123-1-kasturi.shekar%40siemens.com.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] installer: extract backend helpers to sys_api.sh
2026-04-27 6:39 [PATCH 0/4] installer: separate installer into backend, UI, and flow modules 'Kasturi shekar' via isar-users
@ 2026-04-27 6:39 ` 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 2/4] installer: extract attended UI to installer_ui.sh 'Kasturi shekar' via isar-users
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: 'Kasturi shekar' via isar-users @ 2026-04-27 6:39 UTC (permalink / raw)
To: isar-users; +Cc: kasturi.shekar
From: "kasturi.shekar" <kasturi.shekar@siemens.com>
Move backend and system-facing installer logic into sys_api.sh
This patch introduces backend helper APIs for:
- install image discovery
- target device discovery and filtering
- root/live-device exclusion
- RAID member and inactive md filtering
- block device state and size helpers
- bmap copy execution with locking and progress pipe support
Signed-off-by: kasturi.shekar <kasturi.shekar@siemens.com>
---
.../deploy-image/files/usr/bin/sys_api.sh | 400 +++++++++++++++---
1 file changed, 333 insertions(+), 67 deletions(-)
diff --git a/meta-isar/recipes-installer/deploy-image/files/usr/bin/sys_api.sh b/meta-isar/recipes-installer/deploy-image/files/usr/bin/sys_api.sh
index b144419e..9c9c5840 100644
--- a/meta-isar/recipes-installer/deploy-image/files/usr/bin/sys_api.sh
+++ b/meta-isar/recipes-installer/deploy-image/files/usr/bin/sys_api.sh
@@ -1,84 +1,350 @@
#!/usr/bin/env bash
+# This software is a part of ISAR.
+# Copyright (C) Siemens AG, 2026
#
-# sys_api.sh — Ported installer system APIs
-# -------------------------------------------------------------------
+# SPDX-License-Identifier: MIT
-# Load shared framework utilities
-source ./func.sh || {
- echo "Error: func.sh not found or not readable." >&2
- exit 1
+#--------------------------------------------------------------------------
+# sys_api.sh - Backend APIs for deploy-image-wic installer.
+#
+# This file intentionally contains only system/backend logic:
+# - image discovery
+# - target device discovery and filtering
+# - low-level install/copy flow
+#
+# UI concerns (dialog boxes, menus, confirmations) are implemented in
+# installer_ui.sh and called by the main orchestrator script.
+#--------------------------------------------------------------------------
+
+# Globals populated by sys_discover_target_devices().
+SYS_CURRENT_ROOT_DEV=""
+SYS_TARGET_DEVICES=()
+
+#--------------------------------------------------------------------------
+# sys_first_default_image_name <install_data_dir>
+#
+# Returns:
+# basename of matching *.wic* image (excluding *.wic.bmap), or empty.
+#--------------------------------------------------------------------------
+sys_first_default_image_name() {
+ local install_data_dir="$1"
+
+ find "$install_data_dir" -type f -iname "*.wic*" -a -not -iname "*.wic.bmap" \
+ -exec basename {} \; | head -n 1
+}
+
+#--------------------------------------------------------------------------
+# sys_list_installable_entries <install_data_dir>
+#
+# Returns:
+# relative file paths under install_data_dir, one per line.
+# Files ending in *.wic.bmap are excluded.
+#--------------------------------------------------------------------------
+sys_list_installable_entries() {
+ local install_data_dir="$1"
+
+ (
+ cd "$install_data_dir" || return 1
+ find . -type f ! -iname "*.wic.bmap" -print | sed 's#^./##'
+ )
}
-# -------------------------------------------------------------------
-# API: locate_disk_images
-# Description:
-# Find disk image files (.wic, .wic.bz2) under given path.
-# Usage:
-# sys_locate_disk_images search_path=/install
-# Returns JSON:
-# {"error":"", "retval":"0", "images":["/install/image.wic", ...]}
-# -------------------------------------------------------------------
-sys_locate_disk_images() {
- local -A ARGS
- local required=(search_path)
- api_args ARGS required[@] "$@" || {
- pack_return_data error "$_args_error" retval "1"
- return 1
- }
-
- local fn="${FUNCNAME[0]}"
- local path="${ARGS[search_path]}"
-
- log_info "$fn" "Searching for disk images in '$path'"
-
- local images
- images=$(find "$path" -type f -iname "*.wic*" ! -iname "*.wic.bmap" 2>/dev/null)
-
- # when no images found in /install
- if [[ -z "$images" ]]; then
- log_warn "$fn" "No images found."
- pack_return_data error "No images found" retval "1"
- return 1
+#--------------------------------------------------------------------------
+# sys_resolve_image_path <install_data_dir> <image_or_path>
+#
+# Arguments:
+# install_data_dir - base directory where installable images are stored
+# image_or_path - either a relative image filename under install_data_dir
+# or an explicit absolute/relative filesystem path
+#
+# Returns:
+# absolute image path if resolvable, else non-zero return code.
+#--------------------------------------------------------------------------
+sys_resolve_image_path() {
+ local install_data_dir="$1"
+ local image_or_path="$2"
+
+ if [ -f "$image_or_path" ]; then
+ echo "$image_or_path"
+ return 0
+ fi
+
+ if [ -f "$install_data_dir/$image_or_path" ]; then
+ echo "$install_data_dir/$image_or_path"
+ return 0
fi
- # Convert newline-separated paths into JSON array elements
- local json_images
- json_images=$(printf '"%s",' $images | sed 's/,$//')
- # final JSON response on stdout
- echo "{ \"error\":\"\", \"retval\":\"0\", \"images\":[${json_images}] }"
+ return 1
}
+#--------------------------------------------------------------------------
+# sys_discover_target_devices
+#
+# Populates globals:
+# SYS_CURRENT_ROOT_DEV - current live root device identifier
+# SYS_TARGET_DEVICES - array with valid target block devices (/dev/*)
+#
+# Filtering rules match legacy deploy-image-wic behavior, including:
+# - skip installer/live root device and backing devices
+# - skip loop/dm/ram/sr/mtd/zram
+# - skip inactive md arrays and md members
+#--------------------------------------------------------------------------
+sys_discover_target_devices() {
+ local current_root_dev_type
+ local current_root_dev
+ local root_source
+ local root_source_resolved
+ local base_no_part
+ local slave
+ local slave_dev
+ local slave_base
+ local devices
+ local mmc_devices
+ local device
+ local is_raid_member
+ local holder_path
+ local holder_name
+ local state
+ local skip_device
+ local ex
+
+ local exclude_list=()
+
+ SYS_TARGET_DEVICES=()
+
+ # Determine the live root device so we do not offer the current system disk
+ # as an install target. For NFS roots use a special sentinel value.
+
+ current_root_dev_type=$(findmnt / -o fstype -n)
+ if [ "$current_root_dev_type" = "nfs" ]; then
+ current_root_dev="nfs"
+ exclude_list+=("nfs")
+ else
+ root_source=$(findmnt / -o source -n)
+ root_source_resolved=$(readlink -f "$root_source" 2>/dev/null || echo "$root_source")
+ current_root_dev=${root_source_resolved#/dev/}
+
+ exclude_list+=("$current_root_dev")
+
+ # Strip partition suffix for common disk names so the base device
+ # (e.g. /dev/sda or /dev/mmcblk0) also does not become selectable.
+ if [[ "$current_root_dev" =~ ^(mmcblk|nvme) ]]; then
+ base_no_part="${current_root_dev%p[0-9]*}"
+ else
+ base_no_part="${current_root_dev%%[0-9]*}"
+ fi
+
+ if [ -n "$base_no_part" ]; then
+ exclude_list+=("$base_no_part")
+ fi
+
+ # Exclude backing devices for the live root, such as multipath or RAID
+ # underlying devices exposed via /sys/block/<root>/slaves.
+ if [ -d "/sys/block/$current_root_dev/slaves" ]; then
+ for slave in /sys/block/"$current_root_dev"/slaves/*; do
+ [ -e "$slave" ] || continue
+ slave_dev=$(basename "$slave")
+ exclude_list+=("$slave_dev")
+ slave_base=${slave_dev%%[0-9]*}
+ [ -n "$slave_base" ] && exclude_list+=("$slave_base")
+ done
+ fi
+ fi
+
+ SYS_CURRENT_ROOT_DEV="$current_root_dev"
+
+ # Gather block devices from /sys/block while preserving mmcblk devices that
+ # would otherwise be filtered by the main find expression.
+ devices=$(find /sys/block/ -type b,c,f,l -not -iname "mmcblk*" -printf "%f\n") || true
+ mmc_devices=$(find /sys/block/ -type b,c,f,l -iname "mmcblk[0-9]" -printf "%f\n") || true
+ devices="$devices $mmc_devices"
+
+ for device in $devices; do
+ is_raid_member=0
+
+ if [ -d "/sys/block/$device/holders" ] && [ ! -d "/sys/block/$device/md" ]; then
+ for holder_path in /sys/block/$device/holders/*; do
+ holder_name=$(basename "$holder_path")
+ case "$holder_name" in
+ md[0-9]*)
+ is_raid_member=1
+ break
+ ;;
+ esac
+ done
+ fi
+
+ if [ "$is_raid_member" -eq 1 ]; then
+ # Skip RAID member devices, because we only want whole block devices
+ # available for standalone image installation.
+ continue
+ fi
+
+ if [[ "$device" == md* ]]; then
+ # Accept only active or clean md arrays, reject degraded/inactive RAID sets.
+ if [ -f "/sys/block/$device/md/array_state" ]; then
+ state=$(cat /sys/block/$device/md/array_state | tr -d '\n' | tr -d ' ')
+ if [ "$state" != "active" ] && [ "$state" != "clean" ]; then
+ echo "Skipping RAID device $device: state='$state'" >&2
+ continue
+ fi
+ echo "Found RAID device $device: state='$state'" >&2
+ else
+ echo "Skipping RAID device $device: no array_state file" >&2
+ continue
+ fi
+ fi
-# -------------------------------------------------------------------
-# API: sys_list_valid_target_devices
-# Description:
-# Shell-friendly variant of sys_get_valid_target_devices.
-# Prints one valid device per line (absolute path).
-# Usage:
-# sys_list_valid_target_devices
-# Output:
-# /dev/sdb
-# /dev/sdc
-# -------------------------------------------------------------------
-sys_list_valid_target_devices() {
- local dev
-
- for dev in /sys/block/*; do
- dev=$(basename "$dev")
-
- case "$dev" in
- loop*|ram*|sr*|mtd*)
+ case "$device" in
+ dm-*|loop*|mtd*|sr*|ram*|zram*)
continue
;;
esac
- # skip inactive md devices
- if [[ "$dev" == md* ]]; then
- [ -f "/sys/block/$dev/md/array_state" ] || continue
- state=$(cat /sys/block/$dev/md/array_state)
- [ "$state" = "active" ] || [ "$state" = "clean" ] || continue
- fi
+ skip_device=0
+ for ex in "${exclude_list[@]}"; do
+ if [[ "$device" == "$ex"* ]]; then
+ skip_device=1
+ break
+ fi
+ done
- echo "/dev/$dev"
+ if [ "$skip_device" -eq 0 ]; then
+ SYS_TARGET_DEVICES+=("/dev/$device")
+ fi
done
}
+
+#--------------------------------------------------------------------------
+# sys_device_size <device>
+#
+# Returns:
+# human-readable size string from lsblk, or empty if unavailable.
+#--------------------------------------------------------------------------
+sys_device_size() {
+ local device="$1"
+ lsblk --nodeps --noheadings -o SIZE "$device" 2>/dev/null | tr -d " "
+}
+
+#--------------------------------------------------------------------------
+# sys_device_is_empty <device>
+#
+# Returns:
+# 0 when first 1 MiB is zero-filled, 1 otherwise.
+#--------------------------------------------------------------------------
+sys_device_is_empty() {
+ local device="$1"
+ cmp /dev/zero "$device" -n 1M >/dev/null 2>&1
+}
+
+#--------------------------------------------------------------------------
+# sys_version_ge <current> <required>
+#
+# Returns:
+# 0 if current >= required, else 1.
+#--------------------------------------------------------------------------
+sys_version_ge() {
+ local current="$1"
+ local required="$2"
+
+ if [ "$(printf '%s\n' "$current"X "$required" | sort -V | head -n 1)" != "$current"X ]; then
+ return 0
+ fi
+ return 1
+}
+
+#--------------------------------------------------------------------------
+# sys_bmap_options_for_image <image_path>
+#
+# Returns:
+# bmaptool options string ("--nobmap" when no sidecar bmap is present).
+#--------------------------------------------------------------------------
+sys_bmap_options_for_image() {
+ local image_path="$1"
+ local disk_bmap
+
+ disk_bmap="${image_path%.wic*}.wic.bmap"
+ if [ -f "$disk_bmap" ]; then
+ # If a .wic.bmap sidecar exists, return an empty option string so
+ # bmaptool uses the bundled map automatically.
+ echo ""
+ else
+ echo "--nobmap"
+ fi
+}
+
+#--------------------------------------------------------------------------
+# sys_install_image_with_lock <image_path> <target_device>
+#
+# Performs the actual bmaptool copy, serializing concurrent installer
+# consoles via flock. When UI hook functions are available, this API
+# uses them to present a progress gauge in attended mode.
+#
+# Optional UI hooks (if defined):
+# ui_start_progress_gauge <pipe_path>
+# ui_stop_progress_gauge
+#--------------------------------------------------------------------------
+sys_install_image_with_lock() {
+ local image_path="$1"
+ local target_device="$2"
+ local lockfile="/run/installer.lock"
+ local progress_pipe="/run/installer.fifo"
+ local bmap_options
+ local bmap_version
+ local quiet_flag=""
+
+ bmap_options=$(sys_bmap_options_for_image "$image_path")
+
+ exec 9>"$lockfile"
+ if flock -n 9; then
+ bmap_version=$(bmaptool --version | awk '{ print $NF }')
+
+ if sys_version_ge "$bmap_version" "3.6"; then
+ if [ -p "$progress_pipe" ]; then
+ rm -f "$progress_pipe"
+ fi
+
+ if ! mkfifo "$progress_pipe"; then
+ echo "Error: Failed to create named pipe $progress_pipe"
+ return 1
+ fi
+
+ bmap_options="$bmap_options --psplash-pipe=$progress_pipe"
+ quiet_flag="-q"
+
+ if declare -F ui_start_progress_gauge >/dev/null; then
+ ui_start_progress_gauge "$progress_pipe"
+ fi
+ fi
+
+ # Run the actual copying step under the lock to avoid concurrent writes
+ # from multiple installer consoles or sessions.
+ if ! bmaptool $quiet_flag copy $bmap_options "$image_path" "$target_device"; then
+ if declare -F ui_stop_progress_gauge >/dev/null; then
+ ui_stop_progress_gauge
+ fi
+ return 1
+ fi
+
+ if declare -F ui_stop_progress_gauge >/dev/null; then
+ ui_stop_progress_gauge
+ fi
+ else
+ echo "Installation already running in another console."
+ sleep 5
+
+ if [ -e "$progress_pipe" ]; then
+ echo "Installation progress..."
+ tail -f "$progress_pipe" | while read -r line; do
+ printf "\r%s%%" "$line"
+ done
+ else
+ echo "Waiting for installation to finish..."
+ while pgrep -x "bmaptool" >/dev/null; do
+ sleep 5
+ done
+ fi
+ fi
+
+ return 0
+}
--
2.47.3
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260427063957.603123-2-kasturi.shekar%40siemens.com.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/4] installer: extract attended UI to installer_ui.sh
2026-04-27 6:39 [PATCH 0/4] installer: separate installer into backend, UI, and flow modules 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 1/4] installer: extract backend helpers to sys_api.sh 'Kasturi shekar' via isar-users
@ 2026-04-27 6:39 ` 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 3/4] installer: add installer flow module and entrypoint 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 4/4] installer: install seprated installer modules in recipe 'Kasturi shekar' via isar-users
3 siblings, 0 replies; 5+ messages in thread
From: 'Kasturi shekar' via isar-users @ 2026-04-27 6:39 UTC (permalink / raw)
To: isar-users; +Cc: kasturi.shekar
From: "kasturi.shekar" <kasturi.shekar@siemens.com>
Move attended dialog interactions into installer_ui.sh
The new UI module provides:
- image selection menu
- target device selection menu
- install and overwrite confirmation dialogs
- error and info dialogs
- attended progress gauge hooks
Signed-off-by: kasturi.shekar <kasturi.shekar@siemens.com>
---
.../files/usr/bin/installer_ui.sh | 217 +++++++++++++-----
1 file changed, 161 insertions(+), 56 deletions(-)
mode change 100755 => 100644 meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh
diff --git a/meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh b/meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh
old mode 100755
new mode 100644
index 33685c6f..9d3ba5de
--- a/meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh
+++ b/meta-isar/recipes-installer/deploy-image/files/usr/bin/installer_ui.sh
@@ -1,86 +1,191 @@
#!/usr/bin/env bash
+# This software is a part of ISAR.
+# Copyright (C) Siemens AG, 2026
#
-# installer_ui.sh — Attended installer frontend
-# ------------------------------------------------
+# SPDX-License-Identifier: MIT
-SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
-INSTALL_DATA=${INSTALL_DATA:-./install}
+#--------------------------------------------------------------------------
+# installer_ui.sh - Frontend/UI helpers for isar installer.
+#
+# This file is intentionally UI-only:
+# - dialog menus and message boxes
+# - attended confirmations
+# - user abort countdown handling
+#--------------------------------------------------------------------------
+UI_GAUGE_PID=""
+
+#--------------------------------------------------------------------------
+# ui_show_error <message>
+#
+# Displays an error dialog in attended mode.
+#--------------------------------------------------------------------------
+ui_show_error() {
+ local message="$1"
+ dialog --msgbox "$message" 6 60
+}
-# Backend APIs
-. "$SCRIPT_DIR/sys_api.sh"
+#--------------------------------------------------------------------------
+# ui_show_info <message>
+#
+# Displays an informational dialog in attended mode.
+#--------------------------------------------------------------------------
+ui_show_info() {
+ local message="$1"
+ dialog --msgbox "$message" 6 60
+}
+
+#--------------------------------------------------------------------------
+# ui_countdown_allow_attended_switch <seconds> <abort_file>
+#
+# In unattended mode, this gives users a chance to switch to attended
+# mode by pressing any key. Returns 0 when attended mode should be
+# used, and 1 otherwise.
+#--------------------------------------------------------------------------
+ui_countdown_allow_attended_switch() {
+ local timeout="$1"
+ local abort_file="$2"
+ local i
+
+ # Countdown loop prints a message once per second and accepts a key press.
+ # If any key is pressed, create the abort trigger file for the caller.
+ for ((i=timeout; i>0; i--)); do
+ echo -ne "\rUnattended installation will start in $i seconds. Press any key to switch to attended mode..."
+
+ if [ -f "$abort_file" ] || read -n 1 -t 1; then
+ touch "$abort_file"
+ echo
+ return 0
+ fi
+ done
-# ------------------------------------------------
-# Helpers
-# ------------------------------------------------
-die() {
- dialog --msgbox "$1" 6 60
- exit 1
+ echo
+ return 1
}
-# ------------------------------------------------
-# UI: Select image
-# ------------------------------------------------
-ui_select_image() {
- local images json list=()
+#--------------------------------------------------------------------------
+# ui_select_image_menu <install_data_dir>
+#
+# Uses sys_list_installable_entries backend API and returns selected
+# relative image path on stdout.
+#--------------------------------------------------------------------------
+ui_select_image_menu() {
+ local install_data_dir="$1"
+ local list=()
+ local entry
+ local selected
- # On failure, show error dialog and exit
- json=$(sys_locate_disk_images search_path="$INSTALL_DATA") || \
- die "No installable images found in $INSTALL_DATA"
+ while IFS= read -r entry; do
+ [ -n "$entry" ] || continue
+ list+=("$entry" "$entry")
+ done < <(sys_list_installable_entries "$install_data_dir")
- # Extract image paths from JSON
- images=$(echo "$json" | sed -n 's/.*"images":\[\(.*\)\].*/\1/p' | tr -d '"' | tr ',' '\n')
+ if [ "${#list[@]}" -eq 0 ]; then
+ return 1
+ fi
- # Building dialog menu entries
- for img in $images; do
- base=$(basename "$img")
- list+=("$img" "$base")
- done
+ selected=$(dialog --no-tags \
+ --menu "Select image to be installed" 12 70 6 \
+ "${list[@]}" --output-fd 1) || return 2
- # Display menu and capture selection
- INSTALL_IMAGE=$(dialog --no-tags \
- --menu "Select image to install" 10 70 5 \
- "${list[@]}" \
- --output-fd 1) || exit 0
+ echo "$selected"
+ return 0
}
-# ------------------------------------------------
-# UI: Select target device
-# ------------------------------------------------
-ui_select_target_device() {
+#--------------------------------------------------------------------------
+# ui_select_target_device_menu <device...>
+#
+# Displays candidate target devices and returns selected /dev path.
+#--------------------------------------------------------------------------
+ui_select_target_device_menu() {
local list=()
+ local target
+ local target_size
+ local state
+ local selected
- devices=$(sys_list_valid_target_devices) || \
- die "No valid target devices found"
+ for target in "$@"; do
+ [ -b "$target" ] || continue
- for dev in $devices; do
- [ -b "$dev" ] || continue
+ target_size=$(sys_device_size "$target")
+ [ -n "$target_size" ] || target_size="unknown"
- size=$(lsblk --nodeps --noheadings -o SIZE "$dev" 2>/dev/null | tr -d " ")
- [ -z "$size" ] && size="unknown"
-
- if cmp /dev/zero "$dev" -n 1M >/dev/null 2>&1; then
+ # Indicate whether the selected device is already empty, to help users
+ # avoid accidental overwrite of data.
+ if sys_device_is_empty "$target"; then
state="empty"
else
state="contains data"
fi
- list+=("$dev" "$dev ($size, $state)")
+ list+=("$target" "$target ($target_size, $state)")
done
- if [ "${#list[@]}" -lt 2 ]; then
- die "no installable target devices available"
+ if [ "${#list[@]}" -eq 0 ]; then
+ return 1
fi
- TARGET_DEVICE=$(dialog --no-tags \
- --menu "Select target device" 10 70 6 \
- "${list[@]}" \
- --output-fd 1) || exit 0
+ selected=$(dialog --no-tags \
+ --menu "Select device to install image to" 12 70 6 \
+ "${list[@]}" --output-fd 1) || return 2
+
+ echo "$selected"
+ return 0
}
-run_interactive_installer() {
- clear
- ui_select_image
- ui_select_target_device
+#--------------------------------------------------------------------------
+# ui_confirm_install <image_path> <target_device> <target_size>
+#
+# Returns:
+# 0 when user confirms, 1 when canceled.
+#--------------------------------------------------------------------------
+ui_confirm_install() {
+ local image_path="$1"
+ local target_device="$2"
+ local target_size="$3"
+
+ dialog --yes-label Ok --no-label Cancel \
+ --yesno "Start installing\n'$image_path'\nto $target_device (capacity: $target_size)" 8 70
+}
+
+#--------------------------------------------------------------------------
+# ui_confirm_overwrite
+#
+# Returns:
+# 0 when user accepts overwrite, 1 when canceled.
+#--------------------------------------------------------------------------
+ui_confirm_overwrite() {
+ dialog --defaultno --yesno "WARNING: Target device is not empty! Continue anyway?" 8 70
+}
+
+#--------------------------------------------------------------------------
+# ui_start_progress_gauge <pipe_path>
+#
+# Opens a dialog gauge and updates it from bmaptool psplash pipe.
+#--------------------------------------------------------------------------
+ui_start_progress_gauge() {
+ local pipe_path="$1"
+
+ (
+ while true; do
+ if read -r line < "$pipe_path"; then
+ percentage=$(echo "$line" | awk '{ print $2 }')
+ echo "$percentage"
+ fi
+ done
+ ) | dialog --gauge "Flashing image, please wait..." 10 70 0 &
+
+ UI_GAUGE_PID=$!
+}
+
+#--------------------------------------------------------------------------
+# ui_stop_progress_gauge
+#
+# Best-effort termination of the active progress gauge process.
+#--------------------------------------------------------------------------
+ui_stop_progress_gauge() {
+ if [ -n "$UI_GAUGE_PID" ]; then
+ kill "$UI_GAUGE_PID" 2>/dev/null || true
+ UI_GAUGE_PID=""
+ fi
}
-run_interactive_installer
--
2.47.3
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260427063957.603123-3-kasturi.shekar%40siemens.com.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/4] installer: add installer flow module and entrypoint
2026-04-27 6:39 [PATCH 0/4] installer: separate installer into backend, UI, and flow modules 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 1/4] installer: extract backend helpers to sys_api.sh 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 2/4] installer: extract attended UI to installer_ui.sh 'Kasturi shekar' via isar-users
@ 2026-04-27 6:39 ` 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 4/4] installer: install seprated installer modules in recipe 'Kasturi shekar' via isar-users
3 siblings, 0 replies; 5+ messages in thread
From: 'Kasturi shekar' via isar-users @ 2026-04-27 6:39 UTC (permalink / raw)
To: isar-users; +Cc: kasturi.shekar
From: "kasturi.shekar" <kasturi.shekar@siemens.com>
high-level orchestration and keep deploy-image-wic.sh as a thin launcher.
This keeps the externally used script name stable while making the flow easier
to review and maintain by separating:
- backend APIs
- UI frontend
- mode/orchestration flow
Signed-off-by: kasturi.shekar <kasturi.shekar@siemens.com>
---
.../files/usr/bin/deploy-image-wic.sh | 475 +++++++-----------
1 file changed, 192 insertions(+), 283 deletions(-)
mode change 100755 => 100644 meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh
diff --git a/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh b/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh
old mode 100755
new mode 100644
index 60944e58..d128a9b8
--- a/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh
+++ b/meta-isar/recipes-installer/deploy-image/files/usr/bin/deploy-image-wic.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# This software is a part of Isar.
-# Copyright (C) Siemens AG, 2024
+# Copyright (C) Siemens AG, 2026
#
# SPDX-License-Identifier: MIT
@@ -9,293 +9,202 @@ installdata=${INSTALL_DATA:-/install}
SCRIPT_DIR=$( dirname -- "$( readlink -f -- "$0"; )"; )
. "${SCRIPT_DIR}/../lib/deploy-image-wic/handle-config.sh"
+. "${SCRIPT_DIR}/sys_api.sh"
+. "${SCRIPT_DIR}/installer_ui.sh"
-if [ "$installer_unattended" = true ] && [ "$installer_unattended_abort_enable" = true ]; then
- abort_file=/tmp/attended_mode_trigger
- for ((i=$installer_unattended_abort_timeout; i>0; i--)); do
- echo -ne "\rUnattended installation will start in $i seconds. Press any key to switch to attended mode..."
+#--------------------------------------------------------------------------
+# This module contains high-level installer flow logic
+# while keeping low-level backend APIs in sys_api.sh
+# and user-facing dialogs in installer_ui.sh.
+#--------------------------------------------------------------------------
- # Switch to attended mode if the abort file exists or any key pressed during countdown
- # Create abort file to notify all other console instances to abort
- if [ -f "$abort_file" ] || read -n 1 -t 1; then
- installer_unattended=false
- touch "$abort_file"
- break
- fi
- done
-fi
-
-if ! $installer_unattended; then
- installer_image_uri=$(find "$installdata" -type f -iname "*.wic*" -a -not -iname "*.wic.bmap" -exec basename {} \;)
- if [ -z "$installer_image_uri" ] || [ ! -f "$installdata/$installer_image_uri" ]; then
- pushd "$installdata"
- for f in $(find . -type f ! -iname "*.wic.bmap"); do
- array+=("$f" "$f")
- done
- popd
- if [ ${#array[@]} -gt 0 ]; then
- if ! installer_image_uri=$(dialog --no-tags \
- --menu "Select image to be installed" 10 60 3 \
- "${array[@]}" --output-fd 1); then
- exit 0
- fi
- fi
- fi
-
- if [ ! -f "$installdata/$installer_image_uri" ]; then
- dialog --msgbox "Could not find an image to install. Installation aborted." 6 60
- exit 1
- fi
-
- # inspired by poky/meta/recipes-core/initrdscripts/files/install-efi.sh
- target_device_list=""
- current_root_dev_type=$(findmnt / -o fstype -n)
- exclude_list=()
-
- if [ "$current_root_dev_type" = "nfs" ]; then
- current_root_dev="nfs"
- exclude_list+=("nfs")
- else
- # For normal or immutable systems, get the backing device of '/'
- root_source=$(findmnt / -o source -n)
- root_source_resolved=$(readlink -f "$root_source" 2>/dev/null || echo "$root_source")
- current_root_dev=${root_source_resolved#/dev/}
-
- # Always exclude the exact device mounted as /
- exclude_list+=("$current_root_dev")
-
- if [[ "$current_root_dev" =~ ^(mmcblk|nvme) ]]; then
- base_no_part="${current_root_dev%p[0-9]*}"
- else
- base_no_part="${current_root_dev%%[0-9]*}"
- fi
- if [ -n "$base_no_part" ]; then
- exclude_list+=("$base_no_part")
- fi
-
- # If root is coming through a dm-* device (e.g., dm-verity),
- # the actual physical devices appear under /sys/block/<dm>/slaves/.
- # We must exclude those slaves as well, otherwise the installer
- # might show the live USB stick as a valid target.
- if [ -d "/sys/block/$current_root_dev/slaves" ]; then
- for slave in /sys/block/"$current_root_dev"/slaves/*; do
- [ -e "$slave" ] || continue
- slave_dev=$(basename "$slave")
- exclude_list+=("$slave_dev")
- slave_base=${slave_dev%%[0-9]*}
- [ -n "$slave_base" ] && exclude_list+=("$slave_base")
- done
- fi
- fi
-
- echo "Searching for target device..."
-
- devices=$(find /sys/block/ -type b,c,f,l -not -iname "mmcblk*" -printf "%f\n") || true
- mmc_devices=$(find /sys/block/ -type b,c,f,l -iname "mmcblk[0-9]" -printf "%f\n") || true
- devices="$devices $mmc_devices"
-
- for device in $devices; do
- is_raid_member=0
-
- if [ -d "/sys/block/$device/holders" ] && [ ! -d "/sys/block/$device/md" ]; then
- for holder_path in /sys/block/$device/holders/*; do
- holder_name=$(basename "$holder_path")
- case "$holder_name" in
- md[0-9]*)
- is_raid_member=1
- break
- ;;
- esac
- done
- fi
-
- if [ "$is_raid_member" -eq 1 ]; then
- continue # Skip RAID member disks
- fi
-
- if [[ "$device" == md* ]]; then
- if [ -f "/sys/block/$device/md/array_state" ]; then
- state=$(cat /sys/block/$device/md/array_state)
- if [ "$state" != "active" ] && [ "$state" != "clean" ]; then
- continue
- fi
- else
- continue
- fi
- fi
-
- case $device in
- dm-*)
- # skip device-mapper device
- ;;
- loop*)
- # skip loop device
- ;;
- mtd*)
- ;;
- sr*)
- # skip CDROM device
- ;;
- ram*)
- # skip ram device
- ;;
- zram*)
- # skip zram device
- ;;
- *)
- #skip any excluded devices (root and its slaves)
- skip_device=0
- for ex in "${exclude_list[@]}"; do
- if [[ "$device" == "$ex"* ]]; then
- skip_device=1
- break
- fi
- done
-
- if [ "$skip_device" -eq 0 ]; then
- target_device_list="$target_device_list $device"
- fi
- ;;
- esac
- done
-
- if [ -z "${target_device_list}" ]; then
- dialog --msgbox "You need another device (besides the live device /dev/${current_root_dev}) to install the image. Installation aborted." 7 60
- exit 1
- fi
-
- if [ "$(echo "$target_device_list" | wc -w)" -gt 1 ]; then
- array=()
- for target in $(echo "$target_device_list" | xargs -n1 | sort); do
- target_size=$(lsblk --nodeps --noheadings -o SIZE /dev/"$target" | tr -d " ")
- if cmp /dev/zero /dev/"$target" -n 1M; then
- state="empty"
- else
- state="contains data"
- fi
- array+=("/dev/$target" "/dev/$target ($target_size, $state)")
- done
- if ! installer_target_dev=$(dialog --no-tags \
- --menu "Select device to install image to" 10 60 3 \
- "${array[@]}" --output-fd 1); then
- exit 0
- fi
- else
- installer_target_dev="/dev/$(echo "$target_device_list" | tr -d " ")"
- fi
- TARGET_DEVICE_SIZE=$(lsblk --nodeps --noheadings -o SIZE "$installer_target_dev" | tr -d " ")
- if ! dialog --yes-label Ok --no-label Cancel \
- --yesno "Start installing\n'$installer_image_uri'\nto $installer_target_dev (capacity: $TARGET_DEVICE_SIZE)" 7 60; then
- exit 0
- fi
-
- # set absolute paths to be compatible with unattended mode
- installer_image_uri="$installdata/$installer_image_uri"
-fi
-
-if ! cmp /dev/zero "$installer_target_dev" -n 1M; then
- if ! $installer_unattended; then
- if ! dialog --defaultno \
- --yesno "WARNING: Target device is not empty! Continue anyway?" 5 60; then
- exit 0
- fi
- else
- if [ "$installer_target_overwrite" != "OVERWRITE" ]; then
- echo "Target device is not empty! -> Abort"
- echo "If you want to override existing data set \"installer.target.overwrite=OVERWRITE\" on your kernel cmdline or edit your \"auto.install\" file accordingly."
-
- exit 1
- fi
- fi
-fi
-
-bmap_options=""
-
-# bmap file is expected to be next to the installer image
-DISK_BMAP="${installer_image_uri%.wic*}.wic.bmap"
-
-if [ ! -f "$DISK_BMAP" ]; then
- bmap_options="--nobmap"
-fi
-
-if ! $installer_unattended; then
- clear
-fi
-
-# Function to compare version numbers
-version_ge() {
- if [ "$(printf '%s\n' "$1"X "$2" | sort -V | head -n 1)" != "$1"X ]; then
- return 0
- else
- return 1
- fi
+#--------------------------------------------------------------------------
+# flow_run_attended
+#
+# Handles all attended-mode interactions and assigns:
+# installer_image_uri
+# installer_target_dev
+#
+# Returns:
+# 0 on success
+# 1 on hard error
+# 2 on user cancel
+#--------------------------------------------------------------------------
+flow_run_attended() {
+ local default_image
+ local selected_image
+ local selected_target
+ local target_device_size
+
+ default_image=$(sys_first_default_image_name "$installdata")
+ if [ -n "$default_image" ] && [ -f "$installdata/$default_image" ]; then
+ installer_image_uri="$default_image"
+ fi
+
+ if [ -z "$installer_image_uri" ] || [ ! -f "$installdata/$installer_image_uri" ]; then
+ selected_image=$(ui_select_image_menu "$installdata")
+ case $? in
+ 0)
+ installer_image_uri="$selected_image"
+ ;;
+ 1)
+ ui_show_error "Could not find an image to install. Installation aborted."
+ return 1
+ ;;
+ 2)
+ return 2
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+ fi
+
+ if [ ! -f "$installdata/$installer_image_uri" ]; then
+ ui_show_error "Could not find an image to install. Installation aborted."
+ return 1
+ fi
+
+ echo "Searching for target device..."
+ sys_discover_target_devices
+ if [ "${#SYS_TARGET_DEVICES[@]}" -eq 0 ]; then
+ ui_show_error "You need another device (besides the live device /dev/${SYS_CURRENT_ROOT_DEV}) to install the image. Installation aborted."
+ return 1
+ fi
+
+ if [ "${#SYS_TARGET_DEVICES[@]}" -gt 1 ]; then
+ selected_target=$(ui_select_target_device_menu "${SYS_TARGET_DEVICES[@]}")
+ case $? in
+ 0)
+ installer_target_dev="$selected_target"
+ ;;
+ 1)
+ ui_show_error "No installable target devices available. Installation aborted."
+ return 1
+ ;;
+ 2)
+ return 2
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+ else
+ installer_target_dev="${SYS_TARGET_DEVICES[0]}"
+ fi
+
+ target_device_size=$(sys_device_size "$installer_target_dev")
+ if ! ui_confirm_install "$installer_image_uri" "$installer_target_dev" "$target_device_size"; then
+ return 2
+ fi
+
+ installer_image_uri="$installdata/$installer_image_uri"
+ return 0
}
-lockfile="/run/installer.lock"
-progress_pipe="/run/installer.fifo"
-
-exec 9>"$lockfile"
-if flock -n 9; then
- # Get bmap-tools version
- bmap_version=$(bmaptool --version | awk '{ print $NF }')
-
- if version_ge "$bmap_version" "3.6"; then
- if ! mkfifo "$progress_pipe"; then
- echo "Error: Failed to create named pipe $progress_pipe"
- exit 1
- fi
-
- # Add psplash pipe to bmap_options
- bmap_options="$bmap_options --psplash-pipe=$progress_pipe"
- quiet_flag="-q"
-
- # Initialize the dialog gauge and update it dynamically
- (
- while true; do
- if read -r line < "$progress_pipe"; then
- percentage=$(echo "$line" | awk '{ print $2 }')
- echo "$percentage"
- fi
- done
- ) | dialog --gauge "Flashing image, please wait..." 10 70 0 &
-
- gauge_pid=$!
- fi
-
- if ! bmaptool $quiet_flag copy $bmap_options "$installer_image_uri" "$installer_target_dev"; then
- kill "$gauge_pid"
- exit 1
- fi
-
- # Attempt to terminate the gauge process if still running.
- # Errors are ignored since the process may already have exited.
- kill "$gauge_pid" 2>/dev/null
-else
- echo "Installation already running in another console."
+#--------------------------------------------------------------------------
+# flow_validate_target_overwrite_policy
+#
+# Enforces overwrite policy for non-empty targets in both attended and
+# unattended modes.
+#
+# Returns:
+# 0 when policy permits installation
+# 1 when policy rejects installation
+# 2 when user cancels in attended mode
+#--------------------------------------------------------------------------
+flow_validate_target_overwrite_policy() {
+ if sys_device_is_empty "$installer_target_dev"; then
+ return 0
+ fi
+
+ if ! $installer_unattended; then
+ if ! ui_confirm_overwrite; then
+ return 2
+ fi
+ else
+ if [ "$installer_target_overwrite" != "OVERWRITE" ]; then
+ echo "Target device is not empty! -> Abort"
+ echo "If you want to override existing data set \"installer.target.overwrite=OVERWRITE\" on your kernel cmdline or edit your \"auto.install\" file accordingly."
+ return 1
+ fi
+ fi
+
+ return 0
+}
- # Wait for running console to create the progress pipe
- sleep 5
+#--------------------------------------------------------------------------
+# flow_maybe_switch_to_attended
+#
+# If unattended abort-by-key is enabled, this function offers a timeout
+# window to switch to attended mode.
+#--------------------------------------------------------------------------
+flow_maybe_switch_to_attended() {
+ local abort_file
+
+ if [ "$installer_unattended" = true ] && [ "$installer_unattended_abort_enable" = true ]; then
+ abort_file=/tmp/attended_mode_trigger
+ if ui_countdown_allow_attended_switch "$installer_unattended_abort_timeout" "$abort_file"; then
+ installer_unattended=false
+ fi
+ fi
+}
- # Check if progress pipe exists and has content
- if [ -e "$progress_pipe" ]; then
- echo "Installation progress..."
- tail -f "$progress_pipe" | while read line; do
- printf "\r%s%%" "$line"
- done
- else
- # Periodically check if bmaptool is still running every 5 seconds
- echo "Waiting for installation to finish..."
- while pgrep -x "bmaptool" > /dev/null; do
- sleep 5
- done
- fi
-fi
+#--------------------------------------------------------------------------
+# flow_run
+#
+# Main installer flow combining attended/unattended execution paths.
+#--------------------------------------------------------------------------
+flow_run() {
+ flow_maybe_switch_to_attended
+
+ if ! $installer_unattended; then
+ flow_run_attended
+ case $? in
+ 0)
+ ;;
+ 2)
+ return 0
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+ fi
+
+ flow_validate_target_overwrite_policy
+ case $? in
+ 0)
+ ;;
+ 2)
+ return 0
+ ;;
+ *)
+ return 1
+ ;;
+ esac
+
+ if ! $installer_unattended; then
+ clear
+ fi
+
+ if ! sys_install_image_with_lock "$installer_image_uri" "$installer_target_dev"; then
+ if ! $installer_unattended; then
+ ui_show_error "Installation failed."
+ fi
+ return 1
+ fi
+
+ if ! $installer_unattended; then
+ ui_show_info "Installation was successful. System will be rebooted. Please remove the USB stick."
+ else
+ echo "Installation was successful."
+ fi
+
+ return 0
+}
-if ! $installer_unattended; then
- dialog --title "Reboot" \
- --msgbox "Installation was successful. System will be rebooted. Please remove the USB stick." 6 60
-else
- echo "Installation was successful."
-fi
+# Entrypoint: run the installer flow and propagate status.
+flow_run
+exit $?
-exit 0
--
2.47.3
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260427063957.603123-4-kasturi.shekar%40siemens.com.
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 4/4] installer: install seprated installer modules in recipe
2026-04-27 6:39 [PATCH 0/4] installer: separate installer into backend, UI, and flow modules 'Kasturi shekar' via isar-users
` (2 preceding siblings ...)
2026-04-27 6:39 ` [PATCH 3/4] installer: add installer flow module and entrypoint 'Kasturi shekar' via isar-users
@ 2026-04-27 6:39 ` 'Kasturi shekar' via isar-users
3 siblings, 0 replies; 5+ messages in thread
From: 'Kasturi shekar' via isar-users @ 2026-04-27 6:39 UTC (permalink / raw)
To: isar-users; +Cc: kasturi.shekar
From: "kasturi.shekar" <kasturi.shekar@siemens.com>
Update deploy-image recipe to ship the newly split installer modules.
Add the following files to SRC_URI and do_install:
- sys_api.sh
- installer_ui.sh
This finalizes packaging for the refactored installer layout.
Signed-off-by: kasturi.shekar <kasturi.shekar@siemens.com>
---
.../recipes-installer/deploy-image/deploy-image_0.1.bb | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/meta-isar/recipes-installer/deploy-image/deploy-image_0.1.bb b/meta-isar/recipes-installer/deploy-image/deploy-image_0.1.bb
index 03b082a9..ef161ebd 100644
--- a/meta-isar/recipes-installer/deploy-image/deploy-image_0.1.bb
+++ b/meta-isar/recipes-installer/deploy-image/deploy-image_0.1.bb
@@ -1,5 +1,5 @@
# This software is a part of Isar.
-# Copyright (C) Siemens AG, 2024
+# Copyright (C) Siemens AG, 2026
#
# SPDX-License-Identifier: MIT
@@ -9,6 +9,8 @@ MAINTAINER = "isar-users <isar-users@googlegroups.com>"
inherit dpkg-raw
SRC_URI = "file://usr/bin/deploy-image-wic.sh \
+ file://usr/bin/sys_api.sh \
+ file://usr/bin/installer_ui.sh \
file://usr/lib/deploy-image-wic/handle-config.sh \
"
@@ -20,5 +22,7 @@ do_install[cleandirs] = "${D}/usr/bin/ \
"
do_install() {
install -m 0755 ${WORKDIR}/usr/bin/deploy-image-wic.sh ${D}/usr/bin/deploy-image-wic.sh
+ install -m 0755 ${WORKDIR}/usr/bin/sys_api.sh ${D}/usr/bin/sys_api.sh
+ install -m 0755 ${WORKDIR}/usr/bin/installer_ui.sh ${D}/usr/bin/installer_ui.sh
install -m 0755 ${WORKDIR}/usr/lib/deploy-image-wic/handle-config.sh ${D}/usr/lib/deploy-image-wic/handle-config.sh
}
--
2.47.3
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20260427063957.603123-5-kasturi.shekar%40siemens.com.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-27 6:40 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-27 6:39 [PATCH 0/4] installer: separate installer into backend, UI, and flow modules 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 1/4] installer: extract backend helpers to sys_api.sh 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 2/4] installer: extract attended UI to installer_ui.sh 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 3/4] installer: add installer flow module and entrypoint 'Kasturi shekar' via isar-users
2026-04-27 6:39 ` [PATCH 4/4] installer: install seprated installer modules in recipe 'Kasturi shekar' via isar-users
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox