Skip to content
Open
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
66 changes: 66 additions & 0 deletions api/bundles/check_bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import semver

from api.desktop.deps import get_manifest
from api.desktop.installers import get_installers
from api.desktop.installers import get_manifest as get_installer_manifest
from ayon_server.addons.library import AddonLibrary
from ayon_server.exceptions import NotFoundException
from ayon_server.types import Field, OPModel
Expand Down Expand Up @@ -197,5 +200,68 @@ async def check_bundle(
)
)

# Check for Python version installer compatibility with dependency packs
if bundle.dependency_packages:
variant: Literal["production", "staging"] | None = (
"production" if bundle.is_production
else "staging" if bundle.is_staging
else None
)

for platform_name, package_filename in bundle.dependency_packages.items():
if package_filename is None:
continue

try:
manifest = get_manifest(package_filename)
except Exception:
issues.append(
BundleIssueModel(
severity="error",
addon=None,
message=(
f"Dependency package '{package_filename}' manifest could not be loaded."
),
required_addon=None,
)
)
continue

package_python_version = manifest.python_version
if not package_python_version:
continue

installer_list = await get_installers(
bundle.installer_version, platform_name, variant
)
Comment thread
kalisp marked this conversation as resolved.
if not installer_list or not installer_list.installers:
continue

for installer in installer_list.installers:
installer_manifest = get_installer_manifest(installer.filename)
installer_python_version = installer_manifest.python_version
if not installer_python_version:
continue

if is_compatible(
package_python_version, installer_python_version
):
continue

msg = (
f"Dependency package '{package_filename}' requires Python"
f" {package_python_version}, but installer"
f" '{installer.filename}' uses {installer_python_version}"
f" on platform '{platform_name}'."
)
issues.append(
BundleIssueModel(
severity="error",
addon=None,
message=msg,
required_addon=None,
)
)

has_errors = any(issue.severity == "error" for issue in issues)
return CheckBundleResponseModel(success=not has_errors, issues=issues)
84 changes: 47 additions & 37 deletions api/desktop/installers.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,43 +95,9 @@ async def list_installers(
platform: Platform | None = Query(None, description="Platform of the package"),
variant: Literal["production", "staging"] | None = Query(None),
) -> InstallerListModel:
result: list[Installer] = []

if variant in ["production", "staging"]:
r = await Postgres.fetch(
f"""
SELECT data->>'installer_version' as v
FROM bundles WHERE is_{variant} IS TRUE
"""
)
if r:
version = r[0]["v"]
else:
raise NotFoundException(f"No {variant} bundle found")

for filename in iter_names("installers"):
try:
manifest = get_manifest(filename)
except Exception as e:
logger.warning(f"Failed to load manifest file {filename}: {e}")
continue

if filename != manifest.filename:
logger.warning(
f"Filenames in manifest don't match: {filename} != {manifest.filename}"
)
continue

# Filtering

if platform is not None and platform != manifest.platform:
continue

if version is not None and version != manifest.version:
continue

result.append(manifest)
return InstallerListModel(installers=result)
return await get_installers(
version=version, platform=platform, variant=variant
)


@router.post("/installers", status_code=201)
Expand Down Expand Up @@ -263,3 +229,47 @@ async def patch_installer(user: CurrentUser, filename: str, payload: SourcesPatc
async with aiofiles.open(manifest.path, "w") as f:
await f.write(manifest.json(exclude_none=True))
return EmptyResponse(status_code=204)


async def get_installers(
version: str | None = None,
platform: Platform | None = None,
variant: Literal["production", "staging"] | None = None,
) -> InstallerListModel:
result: list[Installer] = []

if variant in ["production", "staging"]:

@iLLiCiTiT iLLiCiTiT Jun 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like dev bundles are not handled? Well, probably are because the logic didn't change, but I wonder how? 🙂

r = await Postgres.fetch(
f"""
SELECT data->>'installer_version' as v
FROM bundles WHERE is_{variant} IS TRUE
"""
)
if r:
version = r[0]["v"]
else:
raise NotFoundException(f"No {variant} bundle found")

for filename in iter_names("installers"):
try:
manifest = get_manifest(filename)
except Exception as e:
logger.warning(f"Failed to load manifest file {filename}: {e}")
continue

if filename != manifest.filename:
logger.warning(
f"Filenames in manifest don't match: {filename} != {manifest.filename}"
)
continue

# Filtering

if platform is not None and platform != manifest.platform:
continue

if version is not None and version != manifest.version:
continue

result.append(manifest)
return InstallerListModel(installers=result)