Repository: archlinux/archinstall

Issue:
Detect if espeakup.service is active in live medium and copy over
When `espeakup.service` is used on the ISO, assume that the user would want that copied over and do so.
I don't think we necessarily need to ask the question in the guided installer, as it would probably be enough to do the detection and act on it.

See discussion on the `argh-general` mailing list: https://lists.archlinux.org/pipermail/arch-general/2021-November/049405.html


Discussion:
This should be fairly easy to do actually,  in addition to making sure that the service is enabled by default, we also need to figure out all the packages necessary and have them installed as part of the base installation, not necessarily the desktop only.  It's kind of a shame that this isn't going to make it in for 2.3.0,  as I don't like that it's not very accessible to blind individuals right now.  The workaround would be to add the additional packages needed during installation and then enable them using the chroot before booting.
I think for speech synthesis it's primarilly [espeak](https://archlinux.org/packages/community/x86_64/espeak/) that needs to be strapped.
If the fix is small, I see no issues incorporating it in v2.3.0.
I blindly assumed that it would require more re-work : )
> I think for speech synthesis it's primarilly [espeak](https://archlinux.org/packages/community/x86_64/espeak/) that needs to be strapped. If the fix is small, I see no issues incorporating it in v2.3.0. I blindly assumed that it would require more re-work : )

I imagine that it's be something like this pseudo code:
```
if espeak.service is running:
    base_packages.append('espeak')
    enable_service('espeak.service')
```
True, I will have to work out the multi-disk-layout dead code path (or simply add an exception to specify that this is in Beta) and then check on the btrfs subvolume issue that's open. So if anyone wants to contribute this for v2.3.0 I'm all for it : ) Otherwise I'll have to do it after those two issues.

Resolving patch:
diff --git a/archinstall/lib/disk/blockdevice.py b/archinstall/lib/disk/blockdevice.py
--- a/archinstall/lib/disk/blockdevice.py
+++ b/archinstall/lib/disk/blockdevice.py
@@ -2,7 +2,6 @@
 import json
 import logging
 import time
-from .helpers import convert_size_to_gb
 from ..exceptions import DiskError
 from ..output import log
 from ..general import SysCommand
@@ -156,6 +155,8 @@ def uuid(self):
 
 	@property
 	def size(self):
+		from .helpers import convert_size_to_gb
+		
 		output = json.loads(SysCommand(f"lsblk --json -b -o+SIZE {self.path}").decode('UTF-8'))
 
 		for device in output['blockdevices']:
diff --git a/archinstall/lib/installer.py b/archinstall/lib/installer.py
--- a/archinstall/lib/installer.py
+++ b/archinstall/lib/installer.py
@@ -25,6 +25,9 @@
 # Any package that the Installer() is responsible for (optional and the default ones)
 __packages__ = ["base", "base-devel", "linux-firmware", "linux", "linux-lts", "linux-zen", "linux-hardened"]
 
+# Additional packages that are installed if the user is running the Live ISO with accessibility tools enabled
+__accessibility_packages__ = ["brltty", "espeakup", "alsa-utils"]
+
 
 class InstallationFile:
 	def __init__(self, installation, filename, owner, mode="w"):
@@ -52,6 +55,10 @@ def poll(self, *args):
 		return self.fh.poll(*args)
 
 
+def accessibility_tools_in_use() -> bool:
+	return os.system('systemctl is-active --quiet espeakup.service') == 0
+
+
 class Installer:
 	"""
 	`Installer()` is the wrapper for most basic installation steps.
@@ -96,6 +103,10 @@ def __init__(self, target, *, base_packages=None, kernels=None):
 		for kernel in kernels:
 			self.base_packages.append(kernel)
 
+		# If using accessibility tools in the live environment, append those to the packages list
+		if accessibility_tools_in_use():
+			self.base_packages.extend(__accessibility_packages__)
+
 		self.post_base_install = []
 
 		storage['session'] = self
@@ -307,6 +318,10 @@ def activate_time_syncronization(self):
 		with Boot(self) as session:
 			session.SysCommand(["timedatectl", "set-ntp", 'true'])
 
+	def enable_espeakup(self):
+		self.log('Enabling espeakup.service for speech synthesis (accessibility).', level=logging.INFO)
+		self.enable_service('espeakup')
+
 	def enable_service(self, *services):
 		for service in services:
 			self.log(f'Enabling service {service}', level=logging.INFO)
@@ -448,7 +463,7 @@ def minimal_installation(self):
 					self.MODULES.append('btrfs')
 				if '/usr/bin/btrfs-progs' not in self.BINARIES:
 					self.BINARIES.append('/usr/bin/btrfs')
-					
+
 			# There is not yet an fsck tool for NTFS. If it's being used for the root filesystem, the hook should be removed.
 			if partition.filesystem == 'ntfs3' and partition.mountpoint == self.target:
 				if 'fsck' in self.HOOKS:
@@ -615,7 +630,7 @@ def add_bootloader(self, bootloader='systemd-bootctl'):
 					self.helper_flags['bootloader'] = bootloader
 
 		elif bootloader == "grub-install":
-			self.pacstrap('grub') # no need?
+			self.pacstrap('grub')  # no need?
 
 			if real_device := self.detect_encryption(root_partition):
 				root_uuid = SysCommand(f"blkid -s UUID -o value {real_device.path}").decode().rstrip()
diff --git a/examples/guided.py b/examples/guided.py
--- a/examples/guided.py
+++ b/examples/guided.py
@@ -334,6 +334,9 @@ def perform_installation(mountpoint):
 			if archinstall.arguments.get('ntp', False):
 				installation.activate_time_syncronization()
 
+			if installation.accessibility_tools_in_use():
+				installation.enable_espeakup()
+
 			if (root_pw := archinstall.arguments.get('!root-password', None)) and len(root_pw):
 				installation.user_set_pw('root', root_pw)
 


Test patch: