music-assistant: dependency fixes (#365751)

This commit is contained in:
Martin Weinelt 2024-12-17 17:15:21 +01:00 committed by GitHub
commit 90607ad948
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 68 additions and 8 deletions

View File

@ -0,0 +1,36 @@
diff --git a/music_assistant/server/helpers/util.py b/music_assistant/server/helpers/util.py
index 3d342b73..a395fb46 100644
--- a/music_assistant/server/helpers/util.py
+++ b/music_assistant/server/helpers/util.py
@@ -117,30 +117,11 @@ async def load_provider_module(domain: str, requirements: list[str]) -> Provider
def _get_provider_module(domain: str) -> ProviderModuleType:
return importlib.import_module(f".{domain}", "music_assistant.server.providers")
- # ensure module requirements are met
- for requirement in requirements:
- if "==" not in requirement:
- # we should really get rid of unpinned requirements
- continue
- package_name, version = requirement.split("==", 1)
- installed_version = await get_package_version(package_name)
- if installed_version == "0.0.0":
- # ignore editable installs
- continue
- if installed_version != version:
- await install_package(requirement)
-
# try to load the module
try:
return await asyncio.to_thread(_get_provider_module, domain)
except ImportError:
- # (re)install ALL requirements
- for requirement in requirements:
- await install_package(requirement)
- # try loading the provider again to be safe
- # this will fail if something else is wrong (as it should)
- return await asyncio.to_thread(_get_provider_module, domain)
-
+ raise RuntimeError(f"Missing dependencies for provider {domain}.")
def create_tempfile():
"""Return a (named) temporary file."""

View File

@ -43,6 +43,9 @@ python.pkgs.buildPythonApplication rec {
ffmpeg = "${lib.getBin ffmpeg-headless}/bin/ffmpeg";
ffprobe = "${lib.getBin ffmpeg-headless}/bin/ffprobe";
})
# Disable interactive dependency resolution, which clashes with the immutable Python environment
./dont-install-deps.patch
];
postPatch = ''

View File

@ -1,5 +1,5 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages (ps: with ps; [ jinja2 mashumaro orjson aiofiles packaging ])" -p pyright ruff isort
#!nix-shell -i python3 -p "python3.withPackages (ps: with ps; [ jinja2 mashumaro orjson aiofiles packaging ])" -p pyright ruff isort nixfmt-rfc-style
import asyncio
import json
import os.path
@ -49,6 +49,7 @@ ROOT: Final = (
.strip()
)
PACKAGE_SET = "music-assistant.python.pkgs"
PACKAGE_MAP = {
"git+https://github.com/MarvinSchenkel/pytube.git": "pytube",
}
@ -167,6 +168,11 @@ def resolve_package_attribute(package: str) -> str:
return matches.pop()
async def get_package_version(package: str) -> str:
version = cast(str, await Nix.eval(f"{PACKAGE_SET}.{package}.version"))
return version
@dataclass
class Provider:
domain: str
@ -180,7 +186,8 @@ class Provider:
return hash(self.domain)
def resolve_providers(manifests) -> Set:
async def resolve_providers(manifests) -> Set:
errors = []
providers = set()
for manifest in manifests:
provider = Provider(manifest.domain)
@ -188,30 +195,44 @@ def resolve_providers(manifests) -> Set:
# allow substituting requirement specifications that packaging cannot parse
if requirement in PACKAGE_MAP:
requirement = PACKAGE_MAP[requirement]
requirement = Requirement(requirement)
try:
provider.available.append(resolve_package_attribute(requirement.name))
attr = resolve_package_attribute(requirement.name)
provider.available.append(attr)
except TooManyMatches as ex:
print(ex, file=sys.stderr)
provider.missing.append(requirement.name)
continue
except NoMatch:
provider.missing.append(requirement.name)
continue
version = await get_package_version(attr)
if version not in requirement.specifier:
errors.append(f"{requirement} not satisifed by version {version}")
providers.add(provider)
if errors:
print("\n - ", end="")
print("\n - ".join(errors))
return providers
def render(version: str, providers: Set):
path = os.path.join(ROOT, "pkgs/by-name/mu/music-assistant/providers.nix")
def render(outpath: str, version: str, providers: Set):
env = Environment()
template = env.from_string(TEMPLATE)
template.stream(version=version, providers=providers).dump(path)
template.stream(version=version, providers=providers).dump(outpath)
async def main():
version: str = cast(str, await Nix.eval("music-assistant.version"))
manifests = await get_provider_manifests(version)
providers = resolve_providers(manifests)
render(version, providers)
providers = await resolve_providers(manifests)
outpath = os.path.join(ROOT, "pkgs/by-name/mu/music-assistant/providers.nix")
render(outpath, version, providers)
run_sync(["nixfmt", outpath])
if __name__ == "__main__":