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

pre launch hook for installing AYON extension #6

Merged
merged 33 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2c05f2b
draft: init of settings
Sponge96 Jan 7, 2025
634884d
chore: update version for testing
Sponge96 Jan 7, 2025
2e89b34
chore: updated package version
Sponge96 Jan 7, 2025
8dee23a
fix: default settings missing
Sponge96 Jan 7, 2025
58447c0
chore: reordering of defs
Sponge96 Jan 7, 2025
89e0e9b
draft: init of prelaunch hook
Sponge96 Jan 7, 2025
ed206fe
chore: temp commits - moving envs
r42-jack Jan 7, 2025
36b57f3
draft: installing extension logic
Sponge96 Jan 7, 2025
c6da2be
feat: prototype working
r42-jack Jan 7, 2025
4886cea
feat: dynamic addon path
r42-jack Jan 7, 2025
bc7e8d1
chore: downgraded version
Sponge96 Jan 7, 2025
5251bba
refactor: better naming on hookfile
Sponge96 Jan 7, 2025
ce57576
fix: incorrect version
Sponge96 Jan 7, 2025
d25e419
draft: unzipping .zxp directly to appdata + switching env
r42-jack Jan 8, 2025
13914f1
draft: prototype of unzipping with relevant checks
Sponge96 Jan 8, 2025
7d9b673
feat: unzipping extension to target path
r42-jack Jan 8, 2025
eaf92cd
fix: added check to prevent running on non windows platforms
Sponge96 Jan 8, 2025
096115c
chore: added logging for non windows platform
r42-jack Jan 8, 2025
6b95eea
Merge remote-tracking branch 'origin/develop' into install-hook
kalisp Jan 20, 2025
450ab0a
Added check for extension version and redeploy
kalisp Jan 21, 2025
a8542b8
feat: version compare
r42-jack Jan 21, 2025
3447228
Rename method
kalisp Jan 21, 2025
f7383d7
Remove newline
kalisp Jan 21, 2025
528b1d3
Updated log
kalisp Jan 21, 2025
2794cfd
Merge branch 'install-hook' of https://github.com/Sponge96/ayon-premi…
r42-jack Jan 21, 2025
4883c0c
refactor: type hints
r42-jack Jan 21, 2025
d067c6d
refactor: black-79lines used + move imports to top of file
Sponge96 Jan 21, 2025
161e652
refactor: 79line limit
Sponge96 Jan 21, 2025
63430a6
Update line widths
kalisp Jan 21, 2025
0da13fd
Merge remote-tracking branch 'origin/develop' into install-hook
kalisp Jan 21, 2025
03ec0e4
fix: looking at incorrect version attribute
r42-jack Jan 21, 2025
dd47772
refactor: line limit (again..)
Sponge96 Jan 21, 2025
68f3b87
Removed unnecessary version, ExtensionBundleVersion should be used
kalisp Jan 22, 2025
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
149 changes: 149 additions & 0 deletions client/ayon_premiere/hooks/pre_launch_install_ayon_extension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import os
import platform
from zipfile import ZipFile
import xml.etree.ElementTree as ET
from shutil import rmtree


from ayon_premiere import PREMIERE_ADDON_ROOT
from ayon_applications import PreLaunchHook, LaunchTypes


class InstallAyonExtensionToPremiere(PreLaunchHook):
"""
Automatically 'installs' the AYON Premiere extension.

Checks if Premiere already has the extension in the relevant folder,
will try to create that folder and unzip the extension if not.
"""

app_groups = {"premiere"}

order = 1
launch_types = {LaunchTypes.local}

def execute(self):
try:
settings = self.data["project_settings"][self.host_name]
if not settings["hooks"]["InstallAyonExtensionToPremiere"][
"enabled"
]:
return
self.inner_execute()

except Exception:
self.log.warning(
"Processing of {} crashed.".format(self.__class__.__name__),
exc_info=True,
)

def inner_execute(self):
self.log.info("Installing AYON Premiere extension.")
Sponge96 marked this conversation as resolved.
Show resolved Hide resolved

# Windows only for now.
if not platform.system().lower() == "windows":
self.log.info("Non Windows platform. Cancelling..")
return

target_path = os.path.join(
os.environ["appdata"], r"Adobe\CEP\extensions\io.ynput.PPRO.panel"
)
Sponge96 marked this conversation as resolved.
Show resolved Hide resolved

extension_path = os.path.join(
PREMIERE_ADDON_ROOT,
r"api\extension.zxp",
)

# Extension already installed, compare the versions to see if we need to replace
if os.path.exists(target_path):
self.log.info(
f"The extension already exists at: {target_path}. Comparing versions.."
)
if not self._compare_extension_versions(
target_path, extension_path
):
return

try:
self.log.debug(f"Creating directory: {target_path}")
os.makedirs(target_path, exist_ok=True)

with ZipFile(extension_path, "r") as archive:
archive.extractall(path=target_path)
self.log.info("Successfully installed AYON extension")

except OSError as error:
self.log.warning(f"OS error has occured: {error}")

except PermissionError as error:
self.log.warning(f"Permissions error has occured: {error}")

except Exception as error:
self.log.warning(f"An unexpected error occured: {error}")

def _compare_extension_versions(
self, target_path: str, extension_path: str
) -> bool:
try:
# opens the existing extension manifest to get the Version attribute.
with open(f"{target_path}/CSXS/manifest.xml", "rb") as xml_file:
installed_version = (
ET.parse(xml_file)
.find("*/Extension")
.attrib.get("Version")
)
self.log.debug(
f"Current extension version found: {installed_version}"
)

Sponge96 marked this conversation as resolved.
Show resolved Hide resolved
if not installed_version:
self.log.warning(
"Unable to resolve the currently installed extension version. Cancelling.."
)
return False

# opens the .zxp manifest to get the Version attribute.
with ZipFile(extension_path, "r") as archive:
xml_file = archive.open("CSXS/manifest.xml")
new_version = (
ET.parse(xml_file)
.find("*/Extension")
.attrib.get("Version")
)
if not new_version:
self.log.warning(
"Unable to resolve the new extension version. Cancelling.."
)
self.log.debug(f"New extension version found: {new_version}")

# compare the two versions, a simple == is enough since
# we don't care if the version increments or decrements
# if they match nothing happens.
if installed_version == new_version:
self.log.info("Versions matched. Cancelling..")
return False

# remove the existing addon to prevent any side effects when unzipping later.
self.log.info(
"Version mismatch found. Removing old extensions.."
)
rmtree(target_path)
return True

except PermissionError as error:
self.log.warning(
f"Permissions error has occured while comparing versions: {error}"
)
return False

except OSError as error:
self.log.warning(
f"OS error has occured while comparing versions: {error}"
)
return False

except Exception as error:
self.log.warning(
f"An unexpected error occured when comparing version: {error}"
)
return False
4 changes: 2 additions & 2 deletions server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

from ayon_server.addons import BaseServerAddon

from .settings import MySettings, DEFAULT_VALUES
from .settings import PremiereSettings, DEFAULT_VALUES


class MyAddon(BaseServerAddon):
settings_model: Type[MySettings] = MySettings
settings_model: Type[PremiereSettings] = PremiereSettings

async def get_default_settings(self):
settings_model_cls = self.get_settings_model()
Expand Down
28 changes: 24 additions & 4 deletions server/settings.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
from ayon_server.settings import BaseSettingsModel
from ayon_server.settings import BaseSettingsModel, SettingsField

DEFAULT_VALUES = {}

class HookOptionalModel(BaseSettingsModel):
enabled: bool = SettingsField(False, title="Enabled")

class MySettings(BaseSettingsModel):
pass

class HooksModel(BaseSettingsModel):
InstallAyonExtensionToPremiere: HookOptionalModel = SettingsField(
default_factory=HookOptionalModel,
title="Install AYON Extension",
)


class PremiereSettings(BaseSettingsModel):
hooks: HooksModel = SettingsField(
default_factory=HooksModel, title="Hooks"
)


DEFAULT_VALUES = {
"hooks": {
"InstallAyonExtensionToPremiere": {
"enabled": False,
}
}
}