Skip to content

Commit

Permalink
Improve typehints
Browse files Browse the repository at this point in the history
  • Loading branch information
tsterbak committed Feb 13, 2023
1 parent 4efa9f7 commit bcd3f52
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 65 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ format:
lint:
poetry run ruff openandroidinstaller/ --ignore E501

typing:
poetry run mypy openandroidinstaller/. --ignore-missing-imports

test: format lint
PYTHONPATH=openandroidinstaller:$(PYTHONPATH) poetry run pytest --cov=openandroidinstaller tests/

Expand Down
21 changes: 18 additions & 3 deletions openandroidinstaller/app_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import copy
from pathlib import Path
from typing import List, Optional

from installer_config import _load_config

Expand All @@ -28,7 +29,7 @@ def __init__(
config_path: Path,
bin_path: Path,
test: bool = False,
test_config: str = None,
test_config: Optional[str] = None,
):
self.platform = platform
self.config_path = config_path
Expand All @@ -44,8 +45,22 @@ def __init__(
self.recovery_path = None
self.is_ab = None

# is this still needed?
self.steps = None
# store views
self.default_views: List = []
self.addon_views: List = []
self.final_default_views: List = []

def add_default_views(self, views: List):
"""Add default views to store"""
self.default_views.extend(views)

def add_addon_views(self, views: List):
"""Add addon views to store"""
self.addon_views.extend(views)

def add_final_default_views(self, views: List):
"""Add final default views to store"""
self.final_default_views.extend(views)

def load_config(self, device_code: str):
"""Load the config from file to state by device code."""
Expand Down
16 changes: 9 additions & 7 deletions openandroidinstaller/installer_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# Author: Tobias Sterbak

from pathlib import Path
from typing import List, Optional
from typing import List, Optional, Dict

import schema
import yaml
Expand All @@ -34,10 +34,10 @@ def __init__(
title: str,
type: str,
content: str,
command: str = None,
img: str = None,
allow_skip: bool = False,
link: str = None,
command: Optional[str] = None,
img: Optional[str] = None,
link: Optional[str] = None,
):
self.title = title
self.type = type
Expand All @@ -51,7 +51,7 @@ def __init__(
class InstallerConfig:

# map some detected device codes to their real code.
device_code_mapping = {
device_code_mapping: Dict[str, str] = {
# Sony issues
"C6603": "yuga",
# OnePlus issues
Expand Down Expand Up @@ -80,9 +80,11 @@ def __init__(
self.requirements = requirements
self.device_code = metadata.get("devicecode")
self.twrp_link = metadata.get("twrp-link")
inverted_mapping = dict(map(reversed, self.device_code_mapping.items()))

# manage device codes and alternative device codes/names
inverted_mapping: Dict[str, str] = dict(map(reversed, self.device_code_mapping.items())) # type: ignore
self.alternative_device_code = inverted_mapping.get(
self.device_code, self.device_code
self.device_code, self.device_code # type: ignore
)

@classmethod
Expand Down
25 changes: 14 additions & 11 deletions openandroidinstaller/openandroidinstaller.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import click
import functools
from pathlib import Path
from typing import List

import flet as ft
from flet import (
Expand Down Expand Up @@ -114,24 +115,26 @@ def __init__(self, state: AppState):
self.install_view,
]

self.state.default_views = self.default_views
self.state.final_default_views = self.final_default_views
self.state.final_view = self.final_view

# stack of previous default views for the back-button
self.previous_views = []

# initialize the addon view
self.select_addon_view = AddonsView(
on_confirm=self.to_next_view, state=self.state
)
self.install_addons_view = InstallAddonsView(
on_confirm=self.to_next_view, state=self.state
)
self.state.addon_views = [
self.install_addons_view,
self.select_addon_view,
]

# attach some views to the state to modify and reuse later
self.state.add_default_views(views=self.default_views)
self.state.add_addon_views(
views=[
self.install_addons_view,
self.select_addon_view,
]
)
self.state.add_final_default_views(views=self.final_default_views)

# stack of previous default views for the back-button
self.previous_views: List = []

def build(self):
self.view.controls.append(self.default_views.pop())
Expand Down
Empty file added openandroidinstaller/py.typed
Empty file.
80 changes: 43 additions & 37 deletions openandroidinstaller/tooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,42 +24,46 @@
)
import shlex
from time import sleep
from typing import List, Optional, Union
from typing import List, Optional, Union, Generator, Callable

from loguru import logger


TerminalResponse = Generator[Union[str, bool], None, None]


PLATFORM = sys.platform


def run_command(
command: str, bin_path: Path, enable_logging: bool = True
) -> Union[str, bool]:
full_command: str, bin_path: Path, enable_logging: bool = True
) -> TerminalResponse:
"""Run a command with a tool (adb, fastboot, heimdall)."""
yield f"${command}"
yield f"${full_command}"
# split the command and extract the tool part
tool, *command = shlex.split(command)
tool, *command = shlex.split(full_command)
if tool not in ["adb", "fastboot", "heimdall"]:
raise Exception(f"Unknown tool {tool}. Use adb, fastboot or heimdall.")
if PLATFORM == "win32":
full_command = [str(bin_path.joinpath(Path(f"{tool}"))) + ".exe"] + command
command_list = [str(bin_path.joinpath(Path(f"{tool}"))) + ".exe"] + command
# prevent Windows from opening terminal windows
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
si = subprocess.STARTUPINFO() # type: ignore
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW # type: ignore
else:
full_command = [str(bin_path.joinpath(Path(f"{tool}")))] + command
command_list = [str(bin_path.joinpath(Path(f"{tool}")))] + command
si = None
if enable_logging:
logger.info(f"Run command: {full_command}")
logger.info(f"Run command: {command_list}")
# run the command
with subprocess.Popen(
full_command,
command_list,
stdout=PIPE,
stderr=STDOUT,
bufsize=1,
universal_newlines=True,
startupinfo=si,
) as p:
for line in p.stdout:
for line in p.stdout: # type: ignore
if enable_logging:
logger.info(line.strip())
yield line.strip()
Expand All @@ -68,14 +72,14 @@ def run_command(
yield p.returncode == 0


def add_logging(step_desc: str, return_if_fail: bool = False):
def add_logging(step_desc: str, return_if_fail: bool = False) -> Callable:
"""Logging decorator to wrap functions that yield lines.
Logs the `step_desc`.
"""

def logging_decorator(func):
def logging(*args, **kwargs):
def logging_decorator(func) -> Callable:
def logging(*args, **kwargs) -> TerminalResponse:
logger.info(f"{step_desc} - Paramters: {kwargs}")
for line in func(*args, **kwargs):
if (type(line) == bool) and not line:
Expand All @@ -91,42 +95,42 @@ def logging(*args, **kwargs):


@add_logging("Rebooting device with adb.")
def adb_reboot(bin_path: Path) -> bool:
def adb_reboot(bin_path: Path) -> TerminalResponse:
"""Run adb reboot on the device and return success."""
for line in run_command("adb reboot", bin_path):
yield line


@add_logging("Rebooting device into bootloader with adb.", return_if_fail=True)
def adb_reboot_bootloader(bin_path: Path) -> Union[str, bool]:
def adb_reboot_bootloader(bin_path: Path) -> TerminalResponse:
"""Reboot the device into bootloader and return success."""
for line in run_command("adb reboot bootloader", bin_path):
yield line
sleep(1)


@add_logging("Rebooting device into download mode with adb.")
def adb_reboot_download(bin_path: Path) -> Union[str, bool]:
def adb_reboot_download(bin_path: Path) -> TerminalResponse:
"""Reboot the device into download mode of samsung devices and return success."""
for line in run_command("adb reboot download", bin_path):
yield line


@add_logging("Sideload the target to device with adb.")
def adb_sideload(bin_path: Path, target: str) -> Union[str, bool]:
def adb_sideload(bin_path: Path, target: str) -> TerminalResponse:
"""Sideload the target to device and return success."""
for line in run_command(f"adb sideload {target}", bin_path):
yield line


@add_logging("Activate sideloading in TWRP.", return_if_fail=True)
def activate_sideload(bin_path: Path) -> Union[str, bool]:
def activate_sideload(bin_path: Path) -> TerminalResponse:
"""Activate sideload with adb shell in twrp."""
for line in run_command("adb shell twrp sideload", bin_path):
yield line


def adb_twrp_copy_partitions(bin_path: Path, config_path: Path):
def adb_twrp_copy_partitions(bin_path: Path, config_path: Path) -> TerminalResponse:
# some devices like one plus 6t or motorola moto g7 power need the partitions copied to prevent a hard brick
logger.info("Sideload copy_partitions script with adb.")
# activate sideload
Expand All @@ -146,18 +150,18 @@ def adb_twrp_copy_partitions(bin_path: Path, config_path: Path):
yield line
sleep(7)
# Copy partitions end #
return True
yield True


@add_logging("Perform a factory reset with adb and twrp.", return_if_fail=True)
def adb_twrp_format_data(bin_path: Path):
def adb_twrp_format_data(bin_path: Path) -> TerminalResponse:
"""Perform a factory reset with twrp and adb."""
for line in run_command("adb shell twrp format data", bin_path):
yield line


@add_logging("Wipe the selected partition with adb and twrp.", return_if_fail=True)
def adb_twrp_wipe_partition(bin_path: Path, partition: str):
def adb_twrp_wipe_partition(bin_path: Path, partition: str) -> TerminalResponse:
"""Perform a factory reset with twrp and adb."""
for line in run_command(f"adb shell twrp wipe {partition}", bin_path):
yield line
Expand All @@ -169,8 +173,8 @@ def adb_twrp_wipe_and_install(
config_path: Path,
is_ab: bool,
install_addons=True,
recovery: str = None,
) -> bool:
recovery: Optional[str] = None,
) -> TerminalResponse:
"""Wipe and format data with twrp, then flash os image with adb.
Only works for twrp recovery.
Expand Down Expand Up @@ -237,7 +241,9 @@ def adb_twrp_wipe_and_install(
yield line


def adb_twrp_install_addons(bin_path: Path, addons: List[str], is_ab: bool) -> bool:
def adb_twrp_install_addons(
bin_path: Path, addons: List[str], is_ab: bool
) -> TerminalResponse:
"""Flash addons through adb and twrp.
Only works for twrp recovery.
Expand Down Expand Up @@ -279,42 +285,42 @@ def adb_twrp_install_addons(bin_path: Path, addons: List[str], is_ab: bool) -> b


@add_logging("Switch active boot partitions.", return_if_fail=True)
def fastboot_switch_partition(bin_path: Path) -> Union[str, bool]:
def fastboot_switch_partition(bin_path: Path) -> TerminalResponse:
"""Switch the active boot partition with fastboot."""
for line in run_command("fastboot set_active other", bin_path):
yield line


@add_logging("Unlock the device with fastboot and code.")
def fastboot_unlock_with_code(bin_path: Path, unlock_code: str) -> Union[str, bool]:
def fastboot_unlock_with_code(bin_path: Path, unlock_code: str) -> TerminalResponse:
"""Unlock the device with fastboot and code given."""
for line in run_command(f"fastboot oem unlock {unlock_code}", bin_path):
yield line


@add_logging("Unlock the device with fastboot without code.")
def fastboot_unlock(bin_path: Path) -> Union[str, bool]:
def fastboot_unlock(bin_path: Path) -> TerminalResponse:
"""Unlock the device with fastboot and without code."""
for line in run_command("fastboot flashing unlock", bin_path):
yield line


@add_logging("OEM unlocking the device with fastboot.")
def fastboot_oem_unlock(bin_path: Path) -> Union[str, bool]:
def fastboot_oem_unlock(bin_path: Path) -> TerminalResponse:
"""OEM unlock the device with fastboot and without code."""
for line in run_command("fastboot oem unlock", bin_path):
yield line


@add_logging("Get unlock data with fastboot")
def fastboot_get_unlock_data(bin_path: Path) -> Union[str, bool]:
def fastboot_get_unlock_data(bin_path: Path) -> TerminalResponse:
"""Get the unlock data with fastboot"""
for line in run_command("fastboot oem get_unlock_data", bin_path):
yield line


@add_logging("Rebooting device with fastboot.")
def fastboot_reboot(bin_path: Path) -> Union[str, bool]:
def fastboot_reboot(bin_path: Path) -> TerminalResponse:
"""Reboot with fastboot"""
for line in run_command("fastboot reboot", bin_path):
yield line
Expand All @@ -323,7 +329,7 @@ def fastboot_reboot(bin_path: Path) -> Union[str, bool]:
@add_logging("Flash or boot custom recovery with fastboot.")
def fastboot_flash_recovery(
bin_path: Path, recovery: str, is_ab: bool = True
) -> Union[str, bool]:
) -> TerminalResponse:
"""Temporarily, flash custom recovery with fastboot."""
if is_ab:
logger.info("Boot custom recovery with fastboot.")
Expand All @@ -344,7 +350,7 @@ def fastboot_flash_recovery(
yield line


def fastboot_flash_boot(bin_path: Path, recovery: str) -> bool:
def fastboot_flash_boot(bin_path: Path, recovery: str) -> TerminalResponse:
"""Temporarily, flash custom recovery with fastboot to boot partition."""
logger.info("Flash custom recovery with fastboot.")
for line in run_command(f"fastboot flash boot {recovery}", bin_path):
Expand All @@ -366,7 +372,7 @@ def fastboot_flash_boot(bin_path: Path, recovery: str) -> bool:


@add_logging("Flash custom recovery with heimdall.")
def heimdall_flash_recovery(bin_path: Path, recovery: str) -> Union[str, bool]:
def heimdall_flash_recovery(bin_path: Path, recovery: str) -> TerminalResponse:
"""Temporarily, flash custom recovery with heimdall."""
for line in run_command(
f"heimdall flash --no-reboot --RECOVERY {recovery}", bin_path
Expand Down Expand Up @@ -414,7 +420,7 @@ def search_device(platform: str, bin_path: Path) -> Optional[str]:
return None


def check_ab_partition(platform: str, bin_path: Path) -> Optional[str]:
def check_ab_partition(platform: str, bin_path: Path) -> Optional[bool]:
"""Figure out, if its an a/b-partitioned device."""
logger.info(f"Run on {platform} with {bin_path}...")
try:
Expand Down
Loading

0 comments on commit bcd3f52

Please sign in to comment.