H2T (Host-to-target) installs and prevent host pollution (#3978)

* Add host-to-target (H2T) installation mode detection

- Add running_from_host() function to detect if running from installed system vs ISO
- Function checks for /run/archiso existence (ISO mode) vs host mode
- Add clear logging of installation mode on startup
- Skip keyboard layout changes when running from host system
- Fix Pyright type error in jsonify() by using Any instead of object
- Update README to mention installation from existing system

This enables archinstall to be run from an existing Arch installation
to perform host-to-target installs on other disks/partitions.

* match existing style

* rem debug

* info -> debug
This commit is contained in:
HADEON 2025-12-16 00:59:04 +01:00 committed by GitHub
parent 810a50e46c
commit 6b23eff422
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 28 additions and 5 deletions

View File

@ -6,7 +6,7 @@
[![Lint Python and Find Syntax Errors](https://github.com/archlinux/archinstall/actions/workflows/flake8.yaml/badge.svg)](https://github.com/archlinux/archinstall/actions/workflows/flake8.yaml)
Just another guided/automated [Arch Linux](https://wiki.archlinux.org/index.php/Arch_Linux) installer with a twist.
The installer also doubles as a python library to install Arch Linux and manage services, packages, and other things inside the installed system *(Usually from a live medium)*.
The installer also doubles as a python library to install Arch Linux and manage services, packages, and other things inside the installed system *(Usually from a live medium or from an existing installation)*.
* archinstall [discord](https://discord.gg/aDeMffrxNg) server
* archinstall [#archinstall:matrix.org](https://matrix.to/#/#archinstall:matrix.org) Matrix channel

View File

@ -13,6 +13,7 @@ from archinstall.lib.networking import ping
from archinstall.lib.packages.packages import check_package_upgrade
from archinstall.tui.ui.components import tui as ttui
from .lib.general import running_from_host
from .lib.hardware import SysInfo
from .lib.output import FormattedOutput, debug, error, info, log, warn
from .lib.pacman import Pacman
@ -110,6 +111,12 @@ def main() -> int:
info(new_version)
time.sleep(3)
if running_from_host():
# log which mode we are using
debug('Running from Host (H2T Mode)...')
else:
debug('Running from ISO (Live Mode)...')
script = arch_config_handler.get_script()
mod_name = f'archinstall.scripts.{script}'

View File

@ -27,6 +27,17 @@ _VT100_ESCAPE_REGEX = r'\x1B\[[?0-9;]*[a-zA-Z]'
_VT100_ESCAPE_REGEX_BYTES = _VT100_ESCAPE_REGEX.encode()
def running_from_host() -> bool:
"""
Check if running from an installed system.
Returns True if running from installed system (host mode) for host-to-target install.
Returns False if /run/archiso exists (ISO mode).
"""
is_host = not Path('/run/archiso').exists()
return is_host
def generate_password(length: int = 64) -> str:
haystack = string.printable # digits, ascii_letters, punctuation (!"#$[] etc) and whitespace
return ''.join(secrets.choice(haystack) for _ in range(length))
@ -46,7 +57,7 @@ def clear_vt100_escape_codes_from_str(data: str) -> str:
return re.sub(_VT100_ESCAPE_REGEX, '', data)
def jsonify(obj: object, safe: bool = True) -> object:
def jsonify(obj: Any, safe: bool = True) -> Any:
"""
Converts objects into json.dumps() compatible nested dictionaries.
Setting safe to True skips dictionary keys starting with a bang (!)
@ -84,7 +95,7 @@ class JSON(json.JSONEncoder, json.JSONDecoder):
"""
@override
def encode(self, o: object) -> str:
def encode(self, o: Any) -> str:
return super().encode(jsonify(o))
@ -94,7 +105,7 @@ class UNSAFE_JSON(json.JSONEncoder, json.JSONDecoder):
"""
@override
def encode(self, o: object) -> str:
def encode(self, o: Any) -> str:
return super().encode(jsonify(o, safe=False))

View File

@ -1,5 +1,5 @@
from ..exceptions import ServiceException, SysCallError
from ..general import SysCommand
from ..general import SysCommand, running_from_host
from ..output import error
@ -79,6 +79,11 @@ def get_kb_layout() -> str:
def set_kb_layout(locale: str) -> bool:
if running_from_host():
# Skip when running from host - no need to change host keymap
# The target installation keymap is set via installer.set_keyboard_language()
return True
if len(locale.strip()):
if not verify_keyboard_layout(locale):
error(f'Invalid keyboard locale specified: {locale}')