File size: 2,844 Bytes
f8c73f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
"""Share one background model scan between workspaces without racing job writes."""
from __future__ import annotations

from copy import deepcopy
from dataclasses import asdict

from PySide6.QtCore import QObject, Signal
from PySide6.QtWidgets import QApplication

from adam.assets import AssetRegistry
from adam.ui.background import BackgroundRead


class AssetRefresh(QObject):
    changed = Signal()

    def __init__(self, assets: AssetRegistry, config) -> None:
        super().__init__(QApplication.instance())
        self.assets = assets
        self.config = config
        self._folders = None
        self.reader = BackgroundRead(self)
        self.reader.ready.connect(self._merge)

    def request(self, *, force: bool = False) -> None:
        folders = deepcopy(self.config.get("tool_folders", {}))
        if self._folders is not None and folders != self._folders:
            force = True
        self._folders = folders
        # Copy only data, not the attached Qt service. Discovery never writes
        # the registry from a worker or mutates objects used by active jobs.
        snapshot = object.__new__(AssetRegistry)
        snapshot.path = self.assets.path
        snapshot.assets = deepcopy(self.assets.assets)
        baseline = {item.id: asdict(item) for item in snapshot.assets}
        settings = deepcopy(self.config.settings)

        def read():
            snapshot.discover(settings, persist=False)
            return baseline, snapshot.assets

        self.reader.request(read, force=force)

    def _merge(self, result) -> None:
        baseline, discovered = result
        current = {item.id: item for item in self.assets.assets}
        paths = {(item.kind, item.path) for item in current.values()}
        merged = []
        for item in discovered:
            existing = current.get(item.id)
            if item.id in baseline:
                if existing is None:
                    continue  # The user removed it while discovery was running.
                merged.append(existing if asdict(existing) != baseline[item.id] else item)
            elif (item.kind, item.path) not in paths:
                merged.append(item)
        retained = {item.id for item in merged}
        for item in current.values():
            if item.id not in retained and (item.id not in baseline or asdict(item) != baseline[item.id]):
                merged.append(item)
        if [asdict(item) for item in merged] != [asdict(item) for item in self.assets.assets]:
            self.assets.assets = merged
            self.assets.save()
            self.changed.emit()


def asset_refresh(assets: AssetRegistry, config) -> AssetRefresh:
    service = getattr(assets, "_ui_refresh", None)
    if service is None:
        service = AssetRefresh(assets, config)
        assets._ui_refresh = service
    return service