#!/usr/bin/env python3 import os import sys from dataclasses import dataclass from typing import List, Optional @dataclass class Dependency: name: str depType: str # screen, braille, input, sound, speech, core moduleName: str checkCommands: Optional[List[str]] = None # Command-line tools to check pythonImports: Optional[List[str]] = None # Python packages to check devicePaths: Optional[List[str]] = None # Device files to check def check_dependency(dep: Dependency) -> bool: """Check if a single dependency is satisfied.""" isAvailable = True if dep.pythonImports: for package in dep.pythonImports: try: moduleName = package.split('.')[0] __import__(moduleName) print(f'{package}: OK') except ImportError: print(f'{package}: FAIL') isAvailable = False if dep.checkCommands: for cmd in dep.checkCommands: if os.path.exists(f'/usr/bin/{cmd}') or os.path.exists(f'/bin/{cmd}'): print(f'{cmd}: OK') else: print(f'{cmd}: FAIL') isAvailable = False if dep.devicePaths: for path in dep.devicePaths: if os.path.exists(path): print(f'{path}: OK') else: print(f'{path}: FAIL') isAvailable = False return isAvailable # Define all dependencies dependencyList = [ # Core dependencies Dependency('FenrirCore', 'core', 'core', pythonImports=['daemonize', 'enchant']), # Screen drivers Dependency('DummyScreen', 'screen', 'dummyDriver'), Dependency('VCSA', 'screen', 'vcsaDriver', pythonImports=['dbus'], devicePaths=['/dev/vcsa']), Dependency('PTY', 'screen', 'ptyDriver', pythonImports=['pyte']), # Braille drivers Dependency('DummyBraille', 'braille', 'dummyDriver'), Dependency('DebugBraille', 'braille', 'debugDriver'), Dependency('BRLAPI', 'braille', 'brlapiDriver', pythonImports=['brlapi']), # Input drivers Dependency('DummyInput', 'input', 'dummyDriver'), Dependency('DebugInput', 'input', 'debugDriver'), Dependency('Evdev', 'input', 'evdevDriver', pythonImports=['evdev', 'evdev.InputDevice', 'evdev.UInput', 'pyudev']), Dependency('PTYInput', 'input', 'ptyDriver', pythonImports=['pyte']), # Sound drivers Dependency('DummySound', 'sound', 'dummyDriver'), Dependency('DebugSound', 'sound', 'debugDriver'), Dependency('GenericSound', 'sound', 'genericDriver', checkCommands=['play', 'sox']), Dependency('GStreamer', 'sound', 'gstreamerDriver', pythonImports=['gi', 'gi.repository.GLib', 'gi.repository.Gst']), # Speech drivers Dependency('DummySpeech', 'speech', 'dummyDriver'), Dependency('DebugSpeech', 'speech', 'debugDriver'), Dependency('Speechd', 'speech', 'speechdDriver', pythonImports=['speechd']), Dependency('GenericSpeech', 'speech', 'genericDriver', checkCommands=['espeak-ng']) ] defaultModules = { 'FenrirCore', 'VCSA', 'DummyBraille', 'Evdev', 'GenericSpeech', 'GenericSound' } def check_all_dependencies(): print('Checking dependencies...\n') availableModules = [] # Group dependencies by type for organized output for depType in ['core', 'screen', 'braille', 'input', 'sound', 'speech']: print(f'{depType.upper()} DRIVERS') print('-' * 20) depsOfType = [d for d in dependencyList if d.depType == depType] for dep in depsOfType: print(f'\nChecking {dep.name}:') if check_dependency(dep): availableModules.append(dep.name) print('') print_summary(availableModules) def print_summary(availableModules: List[str]): print('=' * 20) print('SUMMARY') print('=' * 20) missingModules = defaultModules - set(availableModules) if missingModules: print('Default Setup: FAIL') print('\nUnavailable Default Modules:') for module in missingModules: print(f'- {module}') print('\nYou may need to install the missing dependencies for the modules above or reconfigure fenrir to not use them.') else: print('Default Setup: OK') print('\nAvailable Modules:') for module in availableModules: print(f'- {module}') if __name__ == '__main__': check_all_dependencies()