Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: support for multiple package screens in one config #139

Merged
merged 3 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ jobs:
virtualenvs-create: true
virtualenvs-in-project: true
- name: System Deps
run: sudo apt install libgirepository1.0-dev libgtk-3-dev libadwaita-1-dev
run: |
sudo apt update
sudo apt install libgirepository1.0-dev libgtk-3-dev libadwaita-1-dev
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v3
Expand Down
69 changes: 69 additions & 0 deletions tests/example-multi-package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
title: uBlue First Boot
properties:
mode: "run-on-change"
actions:
pre:
- run: /full/path/to/bin --with --params
- run: /another/command run
- yafti.plugin.flatpak:
install: org.gnome.Calculator
post:
- run: /run/these/commands --after --all --screens
screens:
first-screen:
source: yafti.screen.title
values:
title: "That was pretty cool"
icon: "/path/to/icon"
description: |
Time to play overwatch
can-we-modify-your-flatpaks:
source: yafti.screen.consent
values:
title: Welcome traveler
condition:
run: flatpak remotes --system | grep fedora
description: |
This tool modifies your flatpaks and flatpak sources. If you do not want to do this exit the installer.
For new users just do it (tm)
actions:
- run: flatpak remote-delete fedora --force
- run: flatpak remove --system --noninteractive --all
applications:
source: yafti.screen.package
values:
title: Install flatpaks
show_terminal: true
package_manager: yafti.plugin.flatpak
groups:
Core:
description: All the good stuff
packages:
- Calculator: org.gnome.Calculator
- Firefox: org.mozilla.firefox
Gaming:
description: GAMES GAMES GAMES
default: false
packages:
- Steam: com.valvesoftware.Steam
- Games: org.gnome.Games
applications-two:
source: yafti.screen.package
values:
title: Install more flatpaks
show_terminal: true
package_manager: yafti.plugin.flatpak
groups:
Office:
description: All the work stuff
default: false
packages:
- LibreOffice: org.libreoffice.LibreOffice
- Calendar: org.gnome.Calendar
final-screen:
source: yafti.screen.title
values:
title: "All done"
icon: "/atph/to/icon"
description: |
Thanks for installing, join the community, next steps
25 changes: 9 additions & 16 deletions tests/test_screen_package_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,27 @@


def test_state_set():
state = PackageScreenState()
state = PackageScreenState("test_state_set")
state.set("hello", True)
assert state.get("hello") is True


def test_state_set_fail():
state = PackageScreenState()
state = PackageScreenState("test_state_set_fail")
with pytest.raises(ValidationError):
state.set("hello", "world")


def test_state_load():
input = {"hello": True, "world": False}
state = PackageScreenState()
state = PackageScreenState("test_state_load")
state.load(input)
assert state.get("hello") is True
assert state.get("world") is False


def test_state_from_dict():
input = {"hello": True, "world": False}
state = PackageScreenState.from_dict(input)
assert state.get("hello") is True
assert state.get("world") is False


def test_state_remove():
state = PackageScreenState()
state = PackageScreenState("test_state_remove")
state.set("kenobi", False)
state.set("general", True)
assert state.get("kenobi") is False
Expand All @@ -42,7 +35,7 @@ def test_state_remove():


def test_state_on_off():
state = PackageScreenState()
state = PackageScreenState("test_state_on_off")
state.on("grievous")
assert state.get("grievous") is True
state.off("grievous")
Expand All @@ -55,7 +48,7 @@ def test_state_on_off():


def test_state_toggle():
state = PackageScreenState()
state = PackageScreenState("test_state_toggle")
state.on("chewy")
assert state.get("chewy") is True
state.toggle("chewy")
Expand All @@ -65,13 +58,13 @@ def test_state_toggle():


def test_state_toggle_error():
state = PackageScreenState()
state = PackageScreenState("test_state_toggle_error")
with pytest.raises(KeyError):
state.toggle("barf")


def test_state_get_on():
state = PackageScreenState()
state = PackageScreenState("test_state_get_on")
state.on("chewy")
state.on("han")
state.off("greedo")
Expand All @@ -81,7 +74,7 @@ def test_state_get_on():


def test_state_keys():
state = PackageScreenState()
state = PackageScreenState("test_state_keys")
state.on("AA")
state.on("BB")
state.off("CC")
Expand Down
11 changes: 9 additions & 2 deletions yafti/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""

import logging
from typing import Annotated

import typer
import yaml
Expand All @@ -25,12 +26,18 @@
from yafti.parser import Config


def run(config: typer.FileText = typer.Argument("/etc/yafti.yml"), debug: bool = False):
def run(
config: typer.FileText = typer.Argument("/etc/yafti.yml"),
debug: bool = False,
force_run: Annotated[
bool, typer.Option("-f", "--force", help="Ignore run mode and force run")
] = False,
):
log.set_level(logging.DEBUG if debug else logging.INFO)
log.debug("starting up", config=config, debug=debug)
config = Config.parse_obj(yaml.safe_load(config))
app = Yafti(config)
app.run(None)
app.run(None, force_run=force_run)


def app():
Expand Down
17 changes: 9 additions & 8 deletions yafti/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(self, cfg: Config = None, loop=None):
self.config = cfg
self.loop = loop or gbulb.get_event_loop()

def run(self, *args, **kwargs):
def run(self, *args, force_run: bool = False, **kwargs):
configured_mode = self.config.properties.mode
_p: Path = self.config.properties.path.expanduser()
# TODO(GH-#103): Remove this prior to 1.0 release. Start.
Expand All @@ -43,15 +43,16 @@ def run(self, *args, **kwargs):
_p.unlink()
_old_p.rename(_p)
# TODO(GH-#103): End.
if configured_mode == YaftiRunModes.disable:
return

if configured_mode == YaftiRunModes.changed:
if _p.exists() and _p.read_text() == self.config_sha:
if not force_run:
if configured_mode == YaftiRunModes.disable:
return

if configured_mode == YaftiRunModes.ignore and _p.exists():
return
if configured_mode == YaftiRunModes.changed:
if _p.exists() and _p.read_text() == self.config_sha:
return

if configured_mode == YaftiRunModes.ignore and _p.exists():
return

super().run(*args, **kwargs)

Expand Down
6 changes: 4 additions & 2 deletions yafti/screen/package/screen/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from yafti import log
from yafti.abc import YaftiScreen
from yafti.screen.console import ConsoleScreen
from yafti.screen.package.state import STATE
from yafti.screen.package.state import PackageScreenState

_xml = """\
<?xml version="1.0" encoding="UTF-8"?>
Expand Down Expand Up @@ -77,6 +77,7 @@ class PackageInstallScreen(YaftiScreen, Gtk.Box):

def __init__(
self,
id: str,
title: str = "Package Installation",
package_manager: str = "yafti.plugin.flatpak",
package_manager_defaults: Optional[dict] = None,
Expand All @@ -89,6 +90,7 @@ def __init__(
self.package_manager = PLUGINS.get(package_manager)
self.package_manager_defaults = package_manager_defaults or {}
self.btn_console.connect("clicked", self.toggle_console)
self.state = PackageScreenState(id)

async def on_activate(self):
if self.started or self.already_run:
Expand All @@ -114,7 +116,7 @@ async def do_pulse(self):
def draw(self):
self.console.hide()
self.append(self.console)
packages = [item.replace("pkg:", "") for item in STATE.get_on("pkg:")]
packages = [item.replace("pkg:", "") for item in self.state.get_on("pkg:")]
asyncio.create_task(self.do_pulse())
return self.install(packages)

Expand Down
13 changes: 9 additions & 4 deletions yafti/screen/package/screen/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from yafti.abc import YaftiScreen, YaftiScreenConfig
from yafti.screen.package.models import PackageConfig, PackageGroupConfig
from yafti.screen.package.screen import PackageInstallScreen, PackagePickerScreen
from yafti.screen.package.state import STATE
from yafti.screen.package.utils import parse_packages
from yafti.screen.package.state import PackageScreenState
from yafti.screen.package.utils import parse_packages, generate_fingerprint

_xml = """\
<?xml version="1.0" encoding="UTF-8"?>
Expand Down Expand Up @@ -62,17 +62,22 @@ def __init__(
self.show_terminal = show_terminal
self.package_manager = package_manager
self.package_manager_defaults = package_manager_defaults
STATE.load(parse_packages(self.packages))
self.fingerprint = generate_fingerprint(self.packages)
self.state = PackageScreenState(self.fingerprint)
self.state.load(parse_packages(self.packages))
self.pkg_carousel.connect("page-changed", self.changed)
self.draw()

def draw(self):
self.pkg_carousel.append(
PackagePickerScreen(title=self.title, packages=self.packages)
PackagePickerScreen(
id=self.fingerprint, title=self.title, packages=self.packages
)
)
self.pkg_carousel.append(
PackageInstallScreen(
title=self.title,
id=self.fingerprint,
package_manager=self.package_manager,
package_manager_defaults=self.package_manager_defaults,
)
Expand Down
14 changes: 8 additions & 6 deletions yafti/screen/package/screen/picker.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from yafti import log
from yafti.abc import YaftiScreen
from yafti.screen.dialog import DialogBox
from yafti.screen.package.state import STATE
from yafti.screen.package.state import PackageScreenState
from yafti.screen.utils import find_parent

_xml = """\
Expand Down Expand Up @@ -58,13 +58,15 @@ class Config(BaseModel):

def __init__(
self,
id: str,
title: str,
packages: list | dict,
**kwargs,
):
super().__init__(**kwargs)
self.status_page.set_title(title)
self.packages = packages
self.state = PackageScreenState(id)
self.draw()

def draw(self):
Expand All @@ -76,17 +78,17 @@ def draw(self):
action_row = Adw.ActionRow(title=name, subtitle=details.get("description"))

def state_set(group, _, value):
STATE.set(f"group:{group}", value)
self.state.set(f"group:{group}", value)
d = self.packages.get(group)
for pkg in d.get("packages", []):
for pkg_name in pkg.values():
if isinstance(pkg_name, dict):
pkg_name = json.dumps(pkg_name)
STATE.set(f"pkg:{pkg_name}", value)
self.state.set(f"pkg:{pkg_name}", value)

state_set(name, None, details.get("default", True))
_switcher = Gtk.Switch()
_switcher.set_active(STATE.get(f"group:{name}"))
_switcher.set_active(self.state.get(f"group:{name}"))
_switcher.set_valign(Gtk.Align.CENTER)

state_set_fn = partial(state_set, name)
Expand Down Expand Up @@ -148,12 +150,12 @@ def _build_apps(self, packages: list):
_app_switcher = Gtk.Switch()
if isinstance(pkg, dict):
pkg = json.dumps(pkg)
_app_switcher.set_active(STATE.get(f"pkg:{pkg}"))
_app_switcher.set_active(self.state.get(f"pkg:{pkg}"))
_app_switcher.set_valign(Gtk.Align.CENTER)

def set_state(pkg, btn, value):
log.debug("state-set", pkg=pkg, value=value)
STATE.set(f"pkg:{pkg}", value)
self.state.set(f"pkg:{pkg}", value)

set_state_func = partial(set_state, pkg)
_app_switcher.connect("state-set", set_state_func)
Expand Down
20 changes: 9 additions & 11 deletions yafti/screen/package/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@
class PackageScreenState:
__slots__ = ["state"]

@classmethod
def from_dict(cls, data: dict) -> "PackageScreenState":
self = cls()
self.load(data)
return self
def __new__(cls, id: str):
if not hasattr(cls, "instances"):
cls.instances = {}
if id not in cls.instances:
cls.instances[id] = super(PackageScreenState, cls).__new__(cls)
return cls.instances[id]

def __init__(self, id: str):
self.state = {}

@validate_arguments
def load(self, data: dict):
for k, v in data.items():
self.set(k, v)

def __init__(self):
self.state = {}

@validate_arguments
def remove(self, item: str) -> None:
del self.state[item]
Expand Down Expand Up @@ -53,6 +54,3 @@ def keys(self) -> list[str]:
@validate_arguments
def get(self, item: str) -> bool:
return self.state.get(item)


STATE = PackageScreenState()
Loading