Skip to content

Commit

Permalink
Lgndr: Replace the monkey functions with factories to create them
Browse files Browse the repository at this point in the history
The factories are also usable in Rare's code to create compatible
functions for the callbacks. If they there is no callback they just
log what is happening. It also removes the need for `typing-extentions`
module.
  • Loading branch information
loathingKernel committed Dec 10, 2023
1 parent df0f760 commit fa5294b
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 70 deletions.
2 changes: 1 addition & 1 deletion AppImageBuilder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ script:
# copy Logo
- cp AppDir/usr/src/rare/resources/images/Rare.png AppDir/usr/share/icons/hicolor/256x256/apps/
# Install application dependencies
- python3 -m pip install --ignore-installed --prefix=/usr --root=AppDir pypresence qtawesome legendary-gl orjson typing_extensions
- python3 -m pip install --ignore-installed --prefix=/usr --root=AppDir pypresence qtawesome legendary-gl orjson

AppDir:
path: AppDir
Expand Down
59 changes: 25 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,32 +45,36 @@ Run it via:
There are some AUR packages available:

- [rare](https://aur.archlinux.org/packages/rare) - for stable releases
- [rare-git](https://aur.archlinux.org/packages/rare-git) - for the latest features, which are not in a stable release
- [rare-git](https://aur.archlinux.org/packages/rare-git) - for the latest development version

#### Debian based

- DUR package: [rare](https://mpr.hunterwittenborn.com/packages/rare)
- .deb file in [releases page](https://github.com/Dummerle/Rare/releases)
- `.deb` file in [releases page](https://github.com/Dummerle/Rare/releases)

**Note**:

- pypresence is an optional package. You can install it
from [DUR](https://mpr.hunterwittenborn.com/packages/python3-pypresence) or with pip.
- Do not wonder if some icons look strange, because the official python3-qtawesome package is too old. Many icons were
replaced.
- pypresence is an optional package. You can install it from [DUR](https://mpr.hunterwittenborn.com/packages/python3-pypresence) or with pip.
- Some icons might look strange on Debian based distributions. The official python3-qtawesome package is too old.


### macOS

There is a .dmg file available in [releases page](https://github.com/Dummerle/Rare/releases).
There is a `.dmg` file available in [releases page](https://github.com/Dummerle/Rare/releases).

**Note**: When you launch it, you will see an error, that the package is from an unknown source. You have to enable it
manually in `Settings -> Security and Privacy`. Otherwise, Gatekeeper will block Rare from running.
**Note**: When you launch it, you will see an error, that the package is from an unknown source. You have to enable it manually in `Settings -> Security and Privacy`. Otherwise, Gatekeeper will block Rare from running.

You can also use `pip`.

### Windows

There is an `.msi` installer available in [releases page](https://github.com/Dummerle/Rare/releases).

There is also a semi-portable `.zip` archive in [releases page](https://github.com/Dummerle/Rare/releases) that lets you run Rare without installing it.

**Important**: On recent version of Windows you should have MSVC 2015 installed, you can get it from [here](https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2015-2017-2019-and-2022)

#### Packages

- Rare is available as a [Winget package](https://github.com/microsoft/winget-pkgs/tree/master/manifests/d/Dummerle/Rare)
You can install Rare with the following one-liner:

Expand All @@ -81,10 +85,7 @@ You can install Rare with the following one-liner:

`choco install rare`

- There is a small beta tool for Windows: [Rare Updater](https://github.com/Dummerle/RareUpdater), which installs and updates rare with a single click


*NOTE*: On recent Windows you should have MSVC 2015 installed, you can get it from [here](https://learn.microsoft.com/en-US/cpp/windows/latest-supported-vc-redist?view=msvc-170#visual-studio-2015-2017-2019-and-2022)
- We also have a beta tool for Windows: [Rare Updater](https://github.com/Dummerle/RareUpdater), which installs and updates rare with a single click

### Packages

Expand All @@ -95,7 +96,8 @@ file for macOS.

In the [actions](https://github.com/Dummerle/Rare/actions) tab you can find packages for the latest commits.

**Note**: They might be unstable.
**Note**: They might be unstable and likely broken.


### Installation via pip (platform independent)

Expand All @@ -105,42 +107,31 @@ Linux, Mac and FreeBSD: execute `rare` in your terminal.

Windows: execute `pythonw -m rare` in cmd

It is possible to create a desktop link, or a start menu link. Execute the command above with `--desktop-shortcut`
or `--startmenu-shortcut` option, alternatively you can create them in the settings.
It is possible to create a desktop link, or a start menu link. Execute the command above with `--desktop-shortcut` or `--startmenu-shortcut` option, alternatively you can create them in the settings.

**Note about $PATH**:

On Linux:

`/home/user/.local/bin` must be in your PATH.

On Windows:

`PythonInstallationDirectory\Scripts` must be in your PATH.

On Mac:

`/Users/user/Library/Python/3.x/bin` must be in your PATH.
* On Linux `/home/user/.local/bin` must be in your PATH.
* On Windows `PythonInstallationDirectory\Scripts` must be in your PATH.
* On Mac `/Users/user/Library/Python/3.x/bin` must be in your PATH.


### Run from source

1. Clone the repo: `git clone https://github.com/Dummerle/Rare
2. Change your working directory to the project folder: `cd Rare`
3. Run `pip install -r requirements.txt` to install all required dependencies.
If you want to be able to use the automatic login and Discord pypresence, run `pip install -r requirements-full.txt`
If you are on Arch you can
run `sudo pacman --needed -S python-wheel python-setuptools python-pyqt5 python-qtawesome python-requests python-typing_extensions` and `yay -S legendary`
If you are on FreeBSD you have to install py39-qt5 from the packages: `sudo pkg install py39-qt5`
* If you want to be able to use the automatic login and Discord pypresence, run `pip install -r requirements-full.txt`
* If you are on Arch you can run `sudo pacman --needed -S python-wheel python-setuptools python-pyqt5 python-qtawesome python-requests python-orjson` and `yay -S legendary`
* If you are on FreeBSD you have to install py39-qt5 from the packages: `sudo pkg install py39-qt5`
4. Run `python3 -m rare`

## Contributing

There are several options to contribute.

- If you know Python and PyQt, you can implement new features (Some ideas are in the projects tab).
- You can translate the application in your language: Check our [transifex](https://www.transifex.com/rare-1/rare) page
for that.
- You can translate the application in your language: Check our [transifex](https://www.transifex.com/rare-1/rare) page for that.

More information is available in CONTRIBUTING.md.

Expand Down
2 changes: 0 additions & 2 deletions rare/lgndr/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,6 @@ def uninstall_game(self, args: LgndrUninstallGameArgs) -> None:
# Override logger for the local context to use message as part of the indirect return value
logger = LgndrIndirectLogger(args.indirect_status, self.logger, logging.WARNING)
get_boolean_choice = args.get_boolean_choice_main
# def get_boolean_choice(x, default): return True
if not self.core.lgd.lock_installed():
logger.fatal('Failed to acquire installed data lock, only one instance of Legendary may '
'install/import/move applications at a time.')
Expand Down Expand Up @@ -429,7 +428,6 @@ def _handle_uninstaller(self, igame: InstalledGame, yes=False, args: LgndrUninst
# Override logger for the local context to use message as part of the indirect return value
logger = LgndrIndirectLogger(args.indirect_status, self.logger, logging.WARNING)
get_boolean_choice = args.get_boolean_choice_handler
# def get_boolean_choice(x, default): return True
# noinspection PyShadowingBuiltins
def print(x): self.logger.info(x) if x else None

Expand Down
30 changes: 14 additions & 16 deletions rare/lgndr/glue/arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

from rare.lgndr.glue.monkeys import (
LgndrIndirectStatus,
GetBooleanChoiceProtocol,
get_boolean_choice,
verify_stdout,
get_boolean_choice_factory,
sdl_prompt_factory,
verify_stdout_factory,
ui_update_factory,
DLManagerSignals,
)
from rare.lgndr.models.downloading import UIUpdate
Expand All @@ -33,7 +34,7 @@ class LgndrImportGameArgs:
yes: bool = False
# Rare: Extra arguments
indirect_status: LgndrIndirectStatus = field(default_factory=LgndrIndirectStatus)
get_boolean_choice: GetBooleanChoiceProtocol = get_boolean_choice
get_boolean_choice: Callable[[str, bool], bool] = get_boolean_choice_factory(True)


@dataclass
Expand All @@ -44,16 +45,16 @@ class LgndrUninstallGameArgs:
yes: bool = False
# Rare: Extra arguments
indirect_status: LgndrIndirectStatus = field(default_factory=LgndrIndirectStatus)
get_boolean_choice_main: GetBooleanChoiceProtocol = get_boolean_choice
get_boolean_choice_handler: GetBooleanChoiceProtocol = get_boolean_choice
get_boolean_choice_main: Callable[[str, bool], bool] = get_boolean_choice_factory(True)
get_boolean_choice_handler: Callable[[str, bool], bool] = get_boolean_choice_factory(True)


@dataclass
class LgndrVerifyGameArgs:
app_name: str
# Rare: Extra arguments
indirect_status: LgndrIndirectStatus = field(default_factory=LgndrIndirectStatus)
verify_stdout: Callable[[int, int, float, float], None] = verify_stdout
verify_stdout: Callable[[int, int, float, float], None] = verify_stdout_factory(None)


@dataclass
Expand Down Expand Up @@ -94,14 +95,11 @@ class LgndrInstallGameArgs:
yes: bool = True
# Rare: Extra arguments
indirect_status: LgndrIndirectStatus = field(default_factory=LgndrIndirectStatus)
get_boolean_choice: GetBooleanChoiceProtocol = get_boolean_choice
sdl_prompt: Callable[[str, str], List[str]] = lambda app_name, title: [""]
verify_stdout: Callable[[int, int, float, float], None] = verify_stdout
get_boolean_choice: Callable[[str, bool], bool] = get_boolean_choice_factory(True)
verify_stdout: Callable[[int, int, float, float], None] = verify_stdout_factory(None)

# def __post_init__(self):
# if self.sdl_prompt is None:
# self.sdl_prompt: Callable[[str, str], list] = \
# lambda app_name, title: self.install_tag if self.install_tag is not None else [""]
def __post_init__(self):
self.sdl_prompt: Callable[[Dict, str], List[str]] = sdl_prompt_factory(self.install_tag)


@dataclass
Expand All @@ -119,8 +117,8 @@ class LgndrInstallGameRealArgs:
# Rare: Extra arguments
install_prereqs: bool = False
indirect_status: LgndrIndirectStatus = field(default_factory=LgndrIndirectStatus)
ui_update: Callable[[UIUpdate], None] = lambda ui: None
dlm_signals: DLManagerSignals = DLManagerSignals()
ui_update: Callable[[UIUpdate], None] = ui_update_factory(None)
dlm_signals: DLManagerSignals = field(default_factory=DLManagerSignals)


@dataclass
Expand Down
44 changes: 36 additions & 8 deletions rare/lgndr/glue/monkeys.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,48 @@
import logging
from dataclasses import dataclass
from typing import Callable, List, Optional, Dict

from typing_extensions import Protocol
from rare.lgndr.models.downloading import UIUpdate

logger = logging.getLogger("LgndrMonkeys")

class GetBooleanChoiceProtocol(Protocol):
def __call__(self, prompt: str, default: bool = ...) -> bool:
...

def get_boolean_choice_factory(value: bool = True) -> Callable[[str, bool], bool]:
def get_boolean_choice(prompt: str, default: bool) -> bool:
logger.debug("get_boolean_choice: %s, default: %s, choice: %s", prompt, default, value)
return value
return get_boolean_choice

def get_boolean_choice(prompt: str, default: bool = True) -> bool:
return default

def sdl_prompt_factory(install_tag: Optional[List[str]] = None) -> Callable[[Dict, str], List[str]]:
def sdl_prompt(sdl_data: Dict, title: str) -> List[str]:
logger.debug("sdl_prompt: %s", title)
for key in sdl_data.keys():
logger.debug("%s: %s %s", key, sdl_data[key]["tags"], sdl_data[key]["name"])
tags = install_tag if install_tag is not None else [""]
logger.debug("choice: %s, tags: %s", install_tag, tags)
return tags
return sdl_prompt

def verify_stdout(a0: int, a1: int, a2: float, a3: float) -> None:
print(f"Verification progress: {a0}/{a1} ({a2:.01f}%) [{a3:.1f} MiB/s]\t\r")

def verify_stdout_factory(
callback: Callable[[int, int, float, float], None] = None
) -> Callable[[int, int, float, float], None]:
def verify_stdout(a0: int, a1: int, a2: float, a3: float) -> None:
if callback is not None and callable(callback):
callback(a0, a1, a2, a3)
else:
logger.info("Verification progress: %d/%d (%.01f%%) [%.1f MiB/s]", a0, a1, a2, a3)
return verify_stdout


def ui_update_factory(callback: Callable[[UIUpdate], None] = None) -> Callable[[UIUpdate], None]:
def ui_update(status: UIUpdate) -> None:
if callback is not None and callable(callback):
callback(status)
else:
logger.info("Installation progress: %s", status)
return ui_update


class DLManagerSignals:
Expand Down
7 changes: 1 addition & 6 deletions rare/models/install.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import os
import platform as pf
from dataclasses import dataclass
from datetime import datetime, timedelta
from typing import List, Optional, Callable, Dict, Tuple
from typing import List, Optional, Dict, Tuple

from legendary.models.downloading import AnalysisResult, ConditionCheckResult
from legendary.models.game import Game, InstalledGame
Expand Down Expand Up @@ -35,10 +34,6 @@ class InstallOptionsModel:
silent: bool = False
install_prereqs: bool = False

def __post_init__(self):
self.sdl_prompt: Callable[[str, str], list] = \
lambda app_name, title: self.install_tag if self.install_tag is not None else [""]

def as_install_kwargs(self) -> Dict:
return {
k: getattr(self, k)
Expand Down
5 changes: 5 additions & 0 deletions requirements-flatpak.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
requests
QtAwesome
setuptools
legendary-gl>=0.20.34
pypresence
1 change: 0 additions & 1 deletion requirements-full.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
typing_extensions
requests
PyQt5
QtAwesome
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
typing_extensions
requests
PyQt5
QtAwesome
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"PyQt5",
"QtAwesome",
'pywin32; platform_system == "Windows"',
"typing_extensions"
]

optional_reqs = dict(
Expand Down

0 comments on commit fa5294b

Please sign in to comment.