feat(applications): add support for power-profiles-daemon/tuned as a power management daemon (#4015)
* fix(profiles): install power-profiles-daemon by default in the desktop profile * fix: only install power-profiles-daemon if a battery is detected * chore: clean up has_battery method * fix: make power management daemon a configurable application * fix: make linter happy after merge * fix: fix merge issues * fix: give has_battery a return type to make linter happy * chore: add locale msgids for power management related strings * fix: changes requested in review * fix: cache has_battery result * fix: changes requested in review * fix: just return none directly * fix: add selected power management daemon to applications menu preview
This commit is contained in:
parent
83c9bf06b2
commit
446d23c59d
|
|
@ -0,0 +1,35 @@
|
||||||
|
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}')
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
@ -2,6 +2,7 @@ from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from archinstall.applications.audio import AudioApp
|
from archinstall.applications.audio import AudioApp
|
||||||
from archinstall.applications.bluetooth import BluetoothApp
|
from archinstall.applications.bluetooth import BluetoothApp
|
||||||
|
from archinstall.applications.power_management import PowerManagementApp
|
||||||
from archinstall.applications.print_service import PrintServiceApp
|
from archinstall.applications.print_service import PrintServiceApp
|
||||||
from archinstall.lib.models import Audio
|
from archinstall.lib.models import Audio
|
||||||
from archinstall.lib.models.application import ApplicationConfiguration
|
from archinstall.lib.models.application import ApplicationConfiguration
|
||||||
|
|
@ -26,6 +27,12 @@ class ApplicationHandler:
|
||||||
users,
|
users,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if app_config.power_management_config:
|
||||||
|
PowerManagementApp().install(
|
||||||
|
install_session,
|
||||||
|
app_config.power_management_config,
|
||||||
|
)
|
||||||
|
|
||||||
if app_config.print_service_config and app_config.print_service_config.enabled:
|
if app_config.print_service_config and app_config.print_service_config.enabled:
|
||||||
PrintServiceApp().install(install_session)
|
PrintServiceApp().install(install_session)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,16 @@
|
||||||
from typing import override
|
from typing import override
|
||||||
|
|
||||||
|
from archinstall.lib.hardware import SysInfo
|
||||||
from archinstall.lib.menu.abstract_menu import AbstractSubMenu
|
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.lib.translationhandler import tr
|
||||||
from archinstall.tui.curses_menu import SelectMenu
|
from archinstall.tui.curses_menu import SelectMenu
|
||||||
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
|
from archinstall.tui.menu_item import MenuItem, MenuItemGroup
|
||||||
|
|
@ -54,8 +63,21 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
|
||||||
preview_action=self._prev_print_service,
|
preview_action=self._prev_print_service,
|
||||||
key='print_service_config',
|
key='print_service_config',
|
||||||
),
|
),
|
||||||
|
MenuItem(
|
||||||
|
text=tr('Power management'),
|
||||||
|
action=select_power_management,
|
||||||
|
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")}: {config.power_management.value}'
|
||||||
|
return None
|
||||||
|
|
||||||
def _prev_bluetooth(self, item: MenuItem) -> str | None:
|
def _prev_bluetooth(self, item: MenuItem) -> str | None:
|
||||||
if item.value is not None:
|
if item.value is not None:
|
||||||
bluetooth_config: BluetoothConfiguration = item.value
|
bluetooth_config: BluetoothConfiguration = item.value
|
||||||
|
|
@ -81,6 +103,29 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def select_power_management(preset: PowerManagementConfiguration | None = None) -> PowerManagementConfiguration | None:
|
||||||
|
group = MenuItemGroup.from_enum(PowerManagement)
|
||||||
|
|
||||||
|
if preset:
|
||||||
|
group.set_focus_by_value(preset.power_management)
|
||||||
|
|
||||||
|
result = SelectMenu[PowerManagement](
|
||||||
|
group,
|
||||||
|
allow_skip=True,
|
||||||
|
alignment=Alignment.CENTER,
|
||||||
|
allow_reset=True,
|
||||||
|
frame=FrameProperties.min(tr('Power management')),
|
||||||
|
).run()
|
||||||
|
|
||||||
|
match result.type_:
|
||||||
|
case ResultType.Skip:
|
||||||
|
return preset
|
||||||
|
case ResultType.Selection:
|
||||||
|
return PowerManagementConfiguration(power_management=result.get_value())
|
||||||
|
case ResultType.Reset:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfiguration | None:
|
def select_bluetooth(preset: BluetoothConfiguration | None) -> BluetoothConfiguration | None:
|
||||||
group = MenuItemGroup.yes_no()
|
group = MenuItemGroup.yes_no()
|
||||||
group.focus_item = MenuItem.no()
|
group.focus_item = MenuItem.no()
|
||||||
|
|
|
||||||
|
|
@ -336,6 +336,11 @@ class GlobalMenu(AbstractMenu[None]):
|
||||||
output += tr('Enabled') if app_config.print_service_config.enabled else tr('Disabled')
|
output += tr('Enabled') if app_config.print_service_config.enabled else tr('Disabled')
|
||||||
output += '\n'
|
output += '\n'
|
||||||
|
|
||||||
|
if app_config.power_management_config:
|
||||||
|
power_management_config = app_config.power_management_config
|
||||||
|
output += f'{tr("Power management")}: {power_management_config.power_management.value}'
|
||||||
|
output += '\n'
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,18 @@ class _SysInfo:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def has_battery(self) -> bool:
|
||||||
|
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
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def cpu_info(self) -> dict[str, str]:
|
def cpu_info(self) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
|
|
@ -210,6 +222,10 @@ _sys_info = _SysInfo()
|
||||||
|
|
||||||
|
|
||||||
class SysInfo:
|
class SysInfo:
|
||||||
|
@staticmethod
|
||||||
|
def has_battery() -> bool:
|
||||||
|
return _sys_info.has_battery
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def has_wifi() -> bool:
|
def has_wifi() -> bool:
|
||||||
ifaces = list(list_interfaces().values())
|
ifaces = list(list_interfaces().values())
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,15 @@ from enum import StrEnum, auto
|
||||||
from typing import Any, NotRequired, TypedDict
|
from typing import Any, NotRequired, TypedDict
|
||||||
|
|
||||||
|
|
||||||
|
class PowerManagement(StrEnum):
|
||||||
|
POWER_PROFILES_DAEMON = 'power-profiles-daemon'
|
||||||
|
TUNED = 'tuned'
|
||||||
|
|
||||||
|
|
||||||
|
class PowerManagementConfigSerialization(TypedDict):
|
||||||
|
power_management: str
|
||||||
|
|
||||||
|
|
||||||
class BluetoothConfigSerialization(TypedDict):
|
class BluetoothConfigSerialization(TypedDict):
|
||||||
enabled: bool
|
enabled: bool
|
||||||
|
|
||||||
|
|
@ -32,6 +41,7 @@ class ZramAlgorithm(StrEnum):
|
||||||
class ApplicationSerialization(TypedDict):
|
class ApplicationSerialization(TypedDict):
|
||||||
bluetooth_config: NotRequired[BluetoothConfigSerialization]
|
bluetooth_config: NotRequired[BluetoothConfigSerialization]
|
||||||
audio_config: NotRequired[AudioConfigSerialization]
|
audio_config: NotRequired[AudioConfigSerialization]
|
||||||
|
power_management_config: NotRequired[PowerManagementConfigSerialization]
|
||||||
print_service_config: NotRequired[PrintServiceConfigSerialization]
|
print_service_config: NotRequired[PrintServiceConfigSerialization]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -63,6 +73,22 @@ class BluetoothConfiguration:
|
||||||
return BluetoothConfiguration(arg['enabled'])
|
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
|
@dataclass
|
||||||
class PrintServiceConfiguration:
|
class PrintServiceConfiguration:
|
||||||
enabled: bool
|
enabled: bool
|
||||||
|
|
@ -94,6 +120,7 @@ class ZramConfiguration:
|
||||||
class ApplicationConfiguration:
|
class ApplicationConfiguration:
|
||||||
bluetooth_config: BluetoothConfiguration | None = None
|
bluetooth_config: BluetoothConfiguration | None = None
|
||||||
audio_config: AudioConfiguration | None = None
|
audio_config: AudioConfiguration | None = None
|
||||||
|
power_management_config: PowerManagementConfiguration | None = None
|
||||||
print_service_config: PrintServiceConfiguration | None = None
|
print_service_config: PrintServiceConfiguration | None = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -113,6 +140,9 @@ class ApplicationConfiguration:
|
||||||
if args and (audio_config := args.get('audio_config')) is not None:
|
if args and (audio_config := args.get('audio_config')) is not None:
|
||||||
app_config.audio_config = AudioConfiguration.parse_arg(audio_config)
|
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:
|
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)
|
app_config.print_service_config = PrintServiceConfiguration.parse_arg(print_service_config)
|
||||||
|
|
||||||
|
|
@ -127,6 +157,9 @@ class ApplicationConfiguration:
|
||||||
if self.audio_config:
|
if self.audio_config:
|
||||||
config['audio_config'] = self.audio_config.json()
|
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:
|
if self.print_service_config:
|
||||||
config['print_service_config'] = self.print_service_config.json()
|
config['print_service_config'] = self.print_service_config.json()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1788,6 +1788,9 @@ msgstr ""
|
||||||
msgid "Would you like to configure the print service?"
|
msgid "Would you like to configure the print service?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Power management"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Authentication"
|
msgid "Authentication"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue