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

Replace Addon's Library logic with Rez #29

Closed
wants to merge 8 commits into from
Closed
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ test_*.py
.python-version
.vscode
BUILD_DATE
.venv
venv

53 changes: 21 additions & 32 deletions api/addons/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from fastapi import Query, Request, Response
from nxtools import logging

from ayon_server.addons import AddonLibrary
from ayon_server.addons import AddonLibrary, RezRepo
from ayon_server.addons.models import SourceInfo
from ayon_server.api.dependencies import CurrentUser
from ayon_server.exceptions import (
Expand Down Expand Up @@ -63,56 +63,45 @@ async def list_addons(
) -> AddonList:
"""List all available addons."""

base_url = f"{request.url.scheme}://{request.url.netloc}"
# base_url = f"{request.url.scheme}://{request.url.netloc}"

result = []
library = AddonLibrary.getinstance()
rezrepo = RezRepo.get_instance()

# maybe some ttl here?
active_versions = await library.get_active_versions()
active_versions = await AddonLibrary.get_enabled_addons()

# TODO: for each version, return the information
# whether it has settings (and don't show the addon in the settings editor if not)

for _name, definition in library.data.items():
vers = active_versions.get(definition.name, {})
for addon_name, addon_dict in rezrepo.packages.items():
vers = active_versions.get(addon_name, {})
versions = {}
is_system = False
for version, addon in definition.versions.items():
if addon.system:
addon_title = ""
addon_description = ""

for version_dict in addon_dict.get("versions", []):
((version_number, addon_rez_package),) = version_dict.items()
versions[version_number] = VersionInfo()

if getattr(addon_rez_package, "system", False):
if not user.is_admin:
continue
is_system = True

vinf = {
"has_settings": bool(addon.get_settings_model()),
"has_site_settings": bool(addon.get_site_settings_model()),
"frontend_scopes": addon.frontend_scopes,
}
if details:
vinf["client_pyproject"] = await addon.get_client_pyproject()

source_info = await addon.get_client_source_info(base_url=base_url)
if source_info is None:
pass

elif not all(isinstance(x, SourceInfo) for x in source_info):
logging.error(f"Invalid source info for {addon.name} {version}")
source_info = [x for x in source_info if isinstance(x, SourceInfo)]
vinf["client_source_info"] = source_info
if not addon_title:
addon_title = getattr(addon_rez_package, "nice_name", "")

vinf["services"] = addon.services or None
versions[version] = VersionInfo(**vinf)
if not addon_description:
addon_description = getattr(addon_rez_package, "description", "")

if not versions:
continue

result.append(
AddonListItem(
name=definition.name,
title=definition.friendly_name,
name=addon_name,
title=addon_title if addon_title else addon_name,
versions=versions,
description=definition.__doc__ or "",
description=addon_description if addon_description else "",
production_version=vers.get("production"),
system=is_system or None,
staging_version=vers.get("staging"),
Expand Down
8 changes: 4 additions & 4 deletions api/addons/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async def remove_override(
variant: str = "production",
project_name: str | None = None,
):
if (addon := AddonLibrary.addon(addon_name, addon_version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, addon_version)) is None:
raise NotFoundException(f"Addon {addon_name} {addon_version} not found")

# TODO: ensure the path is not a part of a group
Expand Down Expand Up @@ -62,7 +62,7 @@ async def pin_override(
variant: str = "production",
project_name: str | None = None,
):
if (addon := AddonLibrary.addon(addon_name, addon_version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, addon_version)) is None:
raise NotFoundException(f"Addon {addon_name} {addon_version} not found")

if project_name:
Expand Down Expand Up @@ -136,7 +136,7 @@ async def remove_site_override(
user_name: str,
path: list[str],
):
if (addon := AddonLibrary.addon(addon_name, addon_version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, addon_version)) is None:
raise NotFoundException(f"Addon {addon_name} {addon_version} not found")

overrides = await addon.get_project_site_overrides(project_name, user_name, site_id)
Expand Down Expand Up @@ -171,7 +171,7 @@ async def pin_site_override(
user_name: str,
path: list[str],
):
if (addon := AddonLibrary.addon(addon_name, addon_version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, addon_version)) is None:
raise NotFoundException(f"Addon {addon_name} {addon_version} not found")

overrides = await addon.get_project_site_overrides(project_name, user_name, site_id)
Expand Down
46 changes: 2 additions & 44 deletions api/addons/delete_addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,9 @@
from ayon_server.api.responses import EmptyResponse
from ayon_server.exceptions import AyonException, ForbiddenException, NotFoundException

# from ayon_server.lib.postgres import Postgres
from .router import router


async def delete_addon_directory(addon_name: str, addon_version: str | None = None):
"""Delete an addon or addon version"""

addon_definition = AddonLibrary.get(addon_name)
if addon_definition is None:
raise NotFoundException("Addon not found")

addon_dir = addon_definition.addon_dir
is_empty = not os.listdir(addon_dir)

if not is_empty and addon_version is not None:
addon = addon_definition.versions.get(addon_version)
if addon is None:
raise NotFoundException("Addon version not found")

version_dir = addon.addon_dir
try:
await aioshutil.rmtree(version_dir)
except Exception as e:
raise AyonException(
f"Failed to delete {addon_name} {addon_version} directory: {e}"
)
AddonLibrary.unload_addon(addon_name, addon_version, {"error": "Addon deleted"})

is_empty = not os.listdir(addon_dir)

if (addon_version is None) or is_empty:
try:
await aioshutil.rmtree(addon_dir)
except Exception as e:
raise AyonException(f"Failed to delete {addon_name} directory: {e}")
AddonLibrary.data.pop(addon_name, None)


@router.delete("/{addon_name}", tags=["Addons"])
async def delete_addon(
user: CurrentUser,
Expand All @@ -57,11 +22,7 @@ async def delete_addon(
if not user.is_admin:
raise ForbiddenException("Only admins can delete addons")

await delete_addon_directory(addon_name)

if purge:
pass
# TODO: implement purge
AddonLibrary.delete_addon_from_server(addon_name)


@router.delete("/{addon_name}/{addon_version}", tags=["Addons"])
Expand All @@ -76,8 +37,5 @@ async def delete_addon_version(
if not user.is_admin:
raise ForbiddenException("Only admins can delete addons")

await delete_addon_directory(addon_name, addon_version)
AddonLibrary.delete_addon_from_server(addon_name, addon_version)

if purge:
pass
# TODO: implement purge
4 changes: 2 additions & 2 deletions api/addons/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from ayon_server.events import dispatch_event, update_event
from ayon_server.exceptions import ForbiddenException
from ayon_server.installer import background_installer
from ayon_server.installer.addons import get_addon_zip_info
from ayon_server.addons import AddonLibrary
from ayon_server.lib.postgres import Postgres
from ayon_server.types import Field, OPModel

Expand Down Expand Up @@ -97,7 +97,7 @@ async def upload_addon_zip_file(

# Get addon name and version from the zip file

addon_name, addon_version = get_addon_zip_info(temp_path)
addon_name, addon_version = AddonLibrary.get_addon_zip_info(temp_path)

# We don't create the event before we know that the zip file is valid
# and contains an addon. If it doesn't, an exception is raised before
Expand Down
12 changes: 5 additions & 7 deletions api/addons/project_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ async def get_addon_project_settings_schema(
site: str | None = Query(None, regex="^[a-z0-9-]+$"),
) -> dict[str, Any]:
"""Return the JSON schema of the addon settings."""

if (addon := AddonLibrary.addon(addon_name, version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, version)) is None:
raise NotFoundException(f"Addon {addon_name} {version} not found")

model = addon.get_settings_model()
Expand Down Expand Up @@ -77,7 +76,7 @@ async def get_addon_project_settings(
variant: str = Query("production"),
site: str | None = Query(None, regex="^[a-z0-9-]+$"),
) -> dict[str, Any]:
if (addon := AddonLibrary.addon(addon_name, version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, version)) is None:
raise NotFoundException(f"Addon {addon_name} {version} not found")

if site:
Expand All @@ -101,7 +100,7 @@ async def get_addon_project_overrides(
variant: str = Query("production"),
site: str | None = Query(None, regex="^[a-z0-9-]+$"),
):
addon = AddonLibrary.addon(addon_name, version)
addon = AddonLibrary.get_addon(addon_name, version)
studio_settings = await addon.get_studio_settings(variant=variant)
if studio_settings is None:
return {}
Expand Down Expand Up @@ -142,8 +141,7 @@ async def set_addon_project_settings(
site: str | None = Query(None, regex="^[a-z0-9-]+$"),
) -> EmptyResponse:
"""Set the studio overrides of the given addon."""

addon = AddonLibrary.addon(addon_name, version)
addon = AddonLibrary.get_addon(addon_name, version)
model = addon.get_settings_model()
if model is None:
raise BadRequestException(f"Addon {addon_name} has no settings")
Expand Down Expand Up @@ -242,7 +240,7 @@ async def delete_addon_project_overrides(
site: str | None = Query(None, regex="^[a-z0-9-]+$"),
):
# Ensure the addon and the project exist
_ = AddonLibrary.addon(addon_name, version)
_ = AddonLibrary.get_addon(addon_name, version)
_ = await ProjectEntity.load(project_name)

if not site:
Expand Down
8 changes: 3 additions & 5 deletions api/addons/site_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ async def get_addon_site_settings_schema(
user: CurrentUser,
) -> dict[str, Any]:
"""Return the JSON schema of the addon site settings."""

if (addon := AddonLibrary.addon(addon_name, version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, version)) is None:
raise NotFoundException(f"Addon {addon_name} {version} not found")

model = addon.get_site_settings_model()
Expand Down Expand Up @@ -54,8 +53,7 @@ async def get_addon_site_settings(
site: str = Query(...),
) -> dict[str, Any]:
"""Return the JSON schema of the addon site settings."""

if (addon := AddonLibrary.addon(addon_name, version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, version)) is None:
raise NotFoundException(f"Addon {addon_name} {version} not found")

model = addon.get_site_settings_model()
Expand Down Expand Up @@ -84,7 +82,7 @@ async def set_addon_site_settings(
user: CurrentUser,
site: str = Query(..., title="Site ID", regex="^[a-z0-9-]+$"),
) -> EmptyResponse:
if (addon := AddonLibrary.addon(addon_name, version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, version)) is None:
raise NotFoundException(f"Addon {addon_name} {version} not found")

model = addon.get_site_settings_model()
Expand Down
12 changes: 5 additions & 7 deletions api/addons/studio_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ async def get_addon_settings_schema(
variant: str = Query("production"),
) -> dict[str, Any]:
"""Return the JSON schema of the addon settings."""

if (addon := AddonLibrary.addon(addon_name, addon_version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, addon_version)) is None:
raise NotFoundException(f"Addon {addon_name} {addon_version} not found")

model = addon.get_settings_model()
Expand Down Expand Up @@ -63,8 +62,7 @@ async def get_addon_studio_settings(
variant: str = Query("production"),
) -> dict[str, Any]:
"""Return the settings (including studio overrides) of the given addon."""

if (addon := AddonLibrary.addon(addon_name, addon_version)) is None:
if (addon := AddonLibrary.get_addon(addon_name, addon_version)) is None:
raise NotFoundException(f"Addon {addon_name} {addon_version} not found")

settings = await addon.get_studio_settings(variant=variant)
Expand All @@ -86,7 +84,7 @@ async def set_addon_studio_settings(
if not user.is_manager:
raise ForbiddenException

addon = AddonLibrary.addon(addon_name, addon_version)
addon = AddonLibrary.get_addon(addon_name, addon_version)
original = await addon.get_studio_settings(variant=variant)
existing = await addon.get_studio_overrides(variant=variant)
model = addon.get_settings_model()
Expand Down Expand Up @@ -143,7 +141,7 @@ async def get_addon_studio_overrides(
if not user.is_manager:
raise ForbiddenException

addon = AddonLibrary.addon(addon_name, addon_version)
addon = AddonLibrary.get_addon(addon_name, addon_version)
settings = await addon.get_studio_settings(variant=variant)
if settings is None:
return {}
Expand All @@ -164,7 +162,7 @@ async def delete_addon_studio_overrides(
raise ForbiddenException

# Ensure addon exists
_ = AddonLibrary.addon(addon_name, addon_version)
_ = get_addon(addon_name, addon_version)

await Postgres.execute(
"""
Expand Down
21 changes: 11 additions & 10 deletions api/bundles/bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,16 +245,17 @@ async def create_new_bundle(
# a bundle with an addon that does not exist
if not addon_version:
continue
_ = AddonLibrary.addon(addon_name, addon_version)

for system_addon_name, addon_definition in AddonLibrary.items():
if addon_definition.is_system:
if system_addon_name not in bundle.addons:
logging.debug(
f"Adding missing system addon {system_addon_name} to bundle {bundle.name}"
)
if addon_definition.latest:
bundle.addons[system_addon_name] = addon_definition.latest.version
_ = AddonLibrary.get_addon(addon_name, addon_version)

# TODO reimplement so it looks at the package for this info
# for system_addon_name, addon_definition in rezrepo.packages():
# if addon_definition.is_system:
# if system_addon_name not in bundle.addons:
# logging.debug(
# f"Adding missing system addon {system_addon_name} to bundle {bundle.name}"
# )
# if addon_definition.latest:
# bundle.addons[system_addon_name] = addon_definition.latest.version

await create_bundle(bundle, user, x_sender)

Expand Down
10 changes: 3 additions & 7 deletions api/market/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import httpx

from ayon_server.addons.library import AddonLibrary
from ayon_server.addons import AddonLibrary
from ayon_server.config import ayonconfig
from ayon_server.exceptions import ForbiddenException
from ayon_server.helpers.cloud import get_cloud_api_headers
Expand Down Expand Up @@ -41,12 +41,8 @@ async def get_local_latest_addon_versions() -> dict[str, str]:
Used to check if there are new versions available
"""

result = {}
for addon_name, definition in AddonLibrary.items():
if not definition.latest:
continue
result[addon_name] = definition.latest.version
return result
return AddonLibrary.get_addons_latest_versions()



async def get_local_production_addon_versions() -> dict[str, str]:
Expand Down
Loading