refactor: extract the shared foundation into an installable library

The single file extension carried 260 lines of infrastructure under its
four Nemo providers: the config file with live reload, the git query
layer, the TTL cache with .git watching, and repository detection. Any
second extension wanting repository awareness had to repeat all of it.

Move that foundation into a nemoRepoCore package with a deliberate plugin
API rather than whatever the providers happened to leave behind:

  * Config gains layered defaults, so a plugin registers its own keys and
    an empty config file is still a working one
  * RepoInfo gains a root, a named last commit tuple and a summary string
  * RepoCache gains refresh, invalidate and an invalidation callback
  * discovery separates the cheap root check used on every drawn folder
    from the upward walk used by on demand work such as menus
  * nemoFiles collapses the uri scheme and directory guards every
    provider was repeating
  * launchers learn the per emulator flag for running a command
  * version negotiation lets a plugin state the core it was built for

The config file moves to nemo-repo-core.json and is seeded from the old
nemo-repo-emblems.json when one exists, so no key changes name and
nothing needs editing by hand.
This commit is contained in:
dualfroz committed 2026-08-05 20:06:41 +02:00
1 parent d81b502300
commit 4ae3a496af
19 files changed
+871 -708

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
"""Version of the core library and the compatibility check plugins call."""
coreVersion = "1.0.0"
class CoreVersionError(RuntimeError):
"""Raised when the installed core cannot satisfy a plugin's requirement."""
def parseVersion(text):
"""Turn "1.2.3" into (1, 2, 3). Missing components count as zero."""
parts = []
for chunk in str(text).split("."):
digits = "".join(character for character in chunk if character.isdigit())
parts.append(int(digits) if digits else 0)
while len(parts) < 3:
parts.append(0)
return tuple(parts[:3])
def satisfies(installed, minimum):
"""True when `installed` can serve a plugin that asked for `minimum`.
The rule is plain semantic versioning: the major component must match
exactly, and the rest must be greater than or equal to the requirement.
"""
installedParts = parseVersion(installed)
minimumParts = parseVersion(minimum)
if installedParts[0] != minimumParts[0]:
return False
return installedParts >= minimumParts
def requireCore(minimumVersion):
"""Assert that this core is new enough for the calling plugin.
Call it once, at import time, before touching any other core symbol.
Nemo logs the resulting exception and skips the extension, which is the
behaviour we want: a plugin built against a newer core must not load
half-working.
"""
if not satisfies(coreVersion, minimumVersion):
raise CoreVersionError(
"nemo-repo-core %s cannot satisfy the required version %s; "
"update the core library" % (coreVersion, minimumVersion)
)
return coreVersion