Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions archinstall/applications/power_management.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from typing import TYPE_CHECKING

from archinstall.lib.models.application import PowerManagement, PowerManagementConfiguration
from archinstall.lib.output import debug

if TYPE_CHECKING:
from archinstall.lib.installer import Installer


class PowerManagementApp:
@property
def ppd_packages(self) -> list[str]:
return [
'power-profiles-daemon',
]

@property
def tuned_packages(self) -> list[str]:
return [
'tuned',
'tuned-ppd',
]

def install(
self,
install_session: 'Installer',
power_management_config: PowerManagementConfiguration,
) -> None:
debug(f'Installing power management daemon: {power_management_config.power_management.value}')

if power_management_config.power_management == PowerManagement.NO_POWER_MANAGEMENT:
debug('No power management daemon selected, skipping installation.')
return

match power_management_config.power_management:
case PowerManagement.POWER_PROFILES_DAEMON:
install_session.add_additional_packages(self.ppd_packages)
case PowerManagement.TUNED:
install_session.add_additional_packages(self.tuned_packages)
9 changes: 8 additions & 1 deletion archinstall/lib/applications/application_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

from archinstall.applications.audio import AudioApp
from archinstall.applications.bluetooth import BluetoothApp
from archinstall.applications.power_management import PowerManagementApp
from archinstall.applications.print_service import PrintServiceApp
from archinstall.lib.models import Audio
from archinstall.lib.models.application import ApplicationConfiguration
from archinstall.lib.models.application import ApplicationConfiguration, PowerManagement
from archinstall.lib.models.users import User

if TYPE_CHECKING:
Expand All @@ -26,6 +27,12 @@ def install_applications(self, install_session: 'Installer', app_config: Applica
users,
)

if app_config.power_management_config and app_config.power_management_config.power_management != PowerManagement.NO_POWER_MANAGEMENT:
PowerManagementApp().install(
install_session,
app_config.power_management_config,
)

if app_config.print_service_config and app_config.print_service_config.enabled:
PrintServiceApp().install(install_session)

Expand Down
47 changes: 46 additions & 1 deletion archinstall/lib/applications/application_menu.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
from typing import override

from archinstall.lib.hardware import SysInfo
from archinstall.lib.menu.abstract_menu import AbstractSubMenu
from archinstall.lib.models.application import ApplicationConfiguration, Audio, AudioConfiguration, BluetoothConfiguration, PrintServiceConfiguration
from archinstall.lib.models.application import (
ApplicationConfiguration,
Audio,
AudioConfiguration,
BluetoothConfiguration,
PowerManagement,
PowerManagementConfiguration,
PrintServiceConfiguration,
)
from archinstall.lib.translationhandler import tr
from archinstall.tui.curses_menu import SelectMenu
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
Expand Down Expand Up @@ -54,8 +63,21 @@ def _define_menu_options(self) -> list[MenuItem]:
preview_action=self._prev_print_service,
key='print_service_config',
),
MenuItem(
text=tr('Power management daemon'),
action=select_power_management,
Comment thread
This conversation was marked as resolved.
preview_action=self._prev_power_management,
enabled=SysInfo.has_battery(),
key='power_management_config',
),
]

def _prev_power_management(self, item: MenuItem) -> str | None:
if item.value is not None:
config: PowerManagementConfiguration = item.value
return f'{tr("Power management daemon")}: {config.power_management.value}'
return None

def _prev_bluetooth(self, item: MenuItem) -> str | None:
if item.value is not None:
bluetooth_config: BluetoothConfiguration = item.value
Expand All @@ -81,6 +103,29 @@ def _prev_print_service(self, item: MenuItem) -> str | None:
return None


def select_power_management(preset: PowerManagementConfiguration | None = None) -> PowerManagementConfiguration | None:
items = [MenuItem(a.value, value=a) for a in PowerManagement]
Comment thread
This conversation was marked as resolved.
Outdated
group = MenuItemGroup(items)

if preset:
group.set_focus_by_value(preset.power_management)

result = SelectMenu[PowerManagement](
Comment thread
This conversation was marked as resolved.
group,
allow_skip=True,
alignment=Alignment.CENTER,
frame=FrameProperties.min(tr('Power management daemon')),
).run()

match result.type_:
case ResultType.Skip:
return preset
case ResultType.Selection:
return PowerManagementConfiguration(power_management=result.get_value())
case ResultType.Reset:
raise ValueError('Unhandled result type')
Comment thread
This conversation was marked as resolved.
Outdated


def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfiguration | None:
group = MenuItemGroup.yes_no()
group.focus_item = MenuItem.no()
Expand Down
12 changes: 12 additions & 0 deletions archinstall/lib/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,18 @@ def graphics_devices(self) -> dict[str, str]:


class SysInfo:
@staticmethod
def has_battery() -> bool:
Comment thread
This conversation was marked as resolved.
for type_path in Path('/sys/class/power_supply/').glob('*/type'):
try:
with open(type_path) as f:
if f.read().strip() == 'Battery':
return True
except OSError:
continue

return False

@staticmethod
def has_wifi() -> bool:
ifaces = list(list_interfaces().values())
Expand Down
34 changes: 34 additions & 0 deletions archinstall/lib/models/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
from typing import Any, NotRequired, TypedDict


class PowerManagement(StrEnum):
NO_POWER_MANAGEMENT = 'No power management daemon'
Comment thread
This conversation was marked as resolved.
Outdated
POWER_PROFILES_DAEMON = 'power-profiles-daemon'
TUNED = auto()
Comment thread
This conversation was marked as resolved.
Outdated


class PowerManagementConfigSerialization(TypedDict):
power_management: str


class BluetoothConfigSerialization(TypedDict):
enabled: bool

Expand All @@ -24,6 +34,7 @@ class PrintServiceConfigSerialization(TypedDict):
class ApplicationSerialization(TypedDict):
bluetooth_config: NotRequired[BluetoothConfigSerialization]
audio_config: NotRequired[AudioConfigSerialization]
power_management_config: NotRequired[PowerManagementConfigSerialization]
print_service_config: NotRequired[PrintServiceConfigSerialization]


Expand Down Expand Up @@ -55,6 +66,22 @@ def parse_arg(arg: dict[str, Any]) -> 'BluetoothConfiguration':
return BluetoothConfiguration(arg['enabled'])


@dataclass
class PowerManagementConfiguration:
power_management: PowerManagement

def json(self) -> PowerManagementConfigSerialization:
return {
'power_management': self.power_management.value,
}

@staticmethod
def parse_arg(arg: dict[str, Any]) -> 'PowerManagementConfiguration':
return PowerManagementConfiguration(
PowerManagement(arg['power_management']),
)


@dataclass
class PrintServiceConfiguration:
enabled: bool
Expand All @@ -71,6 +98,7 @@ def parse_arg(arg: dict[str, Any]) -> 'PrintServiceConfiguration':
class ApplicationConfiguration:
bluetooth_config: BluetoothConfiguration | None = None
audio_config: AudioConfiguration | None = None
power_management_config: PowerManagementConfiguration | None = None
print_service_config: PrintServiceConfiguration | None = None

@staticmethod
Expand All @@ -90,6 +118,9 @@ def parse_arg(
if args and (audio_config := args.get('audio_config')) is not None:
app_config.audio_config = AudioConfiguration.parse_arg(audio_config)

if args and (power_management_config := args.get('power_management_config')) is not None:
app_config.power_management_config = PowerManagementConfiguration.parse_arg(power_management_config)

if args and (print_service_config := args.get('print_service_config')) is not None:
app_config.print_service_config = PrintServiceConfiguration.parse_arg(print_service_config)

Expand All @@ -104,6 +135,9 @@ def json(self) -> ApplicationSerialization:
if self.audio_config:
config['audio_config'] = self.audio_config.json()

if self.power_management_config:
config['power_management_config'] = self.power_management_config.json()

if self.print_service_config:
config['print_service_config'] = self.print_service_config.json()

Expand Down
3 changes: 3 additions & 0 deletions archinstall/locales/base.pot
Original file line number Diff line number Diff line change
Expand Up @@ -1788,6 +1788,9 @@ msgstr ""
msgid "Would you like to configure the print service?"
msgstr ""

msgid "Power management daemon"
msgstr ""

msgid "Authentication"
msgstr ""

Expand Down