SyncServer: Existence of module is optional (#5413)

* 'get_repre_icons' have optional sync server

* local settings have optional sync server

* sync server is optional in sceneinventory

* sync server is optional in loader tool

* sync server is optional in library loader

* sync server is optional in host dirmap

* sync server is optional in nuke cache

* sync server is optional in integrate plugin

* added "sync_server" back to ignored modules for openpype package

* fix missing variable

* mark syncserver command as deprecated

* define 'SYNC_SERVER_ROOT'

* added method to receive icon paths

* use sync server module to receive icons

* fix scene inventory
This commit is contained in:
Jakub Trllo 2023-08-07 18:48:27 +02:00 committed by GitHub
parent ae3eb37776
commit a31b2d9d77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 142 additions and 117 deletions

View file

@ -338,12 +338,18 @@ def runtests(folder, mark, pyargs, test_data_folder, persist, app_variant,
persist, app_variant, timeout, setup_only)
@main.command()
@main.command(help="DEPRECATED - run sync server")
@click.pass_context
@click.option("-a", "--active_site", required=True,
help="Name of active stie")
def syncserver(active_site):
help="Name of active site")
def syncserver(ctx, active_site):
"""Run sync site server in background.
Deprecated:
This command is deprecated and will be removed in future versions.
Use '~/openpype_console module sync_server syncservice' instead.
Details:
Some Site Sync use cases need to expose site to another one.
For example if majority of artists work in studio, they are not using
SS at all, but if you want to expose published assets to 'studio' site
@ -359,7 +365,10 @@ def syncserver(active_site):
if AYON_SERVER_ENABLED:
raise RuntimeError("AYON does not support 'syncserver' command.")
PypeCommands().syncserver(active_site)
from openpype.modules.sync_server.sync_server_module import (
syncservice)
ctx.invoke(syncservice, active_site=active_site)
@main.command()

View file

@ -32,19 +32,26 @@ class HostDirmap(object):
"""
def __init__(
self, host_name, project_name, project_settings=None, sync_module=None
self,
host_name,
project_name,
project_settings=None,
sync_module=None
):
self.host_name = host_name
self.project_name = project_name
self._project_settings = project_settings
self._sync_module = sync_module # to limit reinit of Modules
self._sync_module = sync_module
# to limit reinit of Modules
self._sync_module_discovered = sync_module is not None
self._log = None
@property
def sync_module(self):
if self._sync_module is None:
if not self._sync_module_discovered:
self._sync_module_discovered = True
manager = ModulesManager()
self._sync_module = manager["sync_server"]
self._sync_module = manager.get("sync_server")
return self._sync_module
@property
@ -151,21 +158,25 @@ class HostDirmap(object):
"""
project_name = self.project_name
sync_module = self.sync_module
mapping = {}
if (not self.sync_module.enabled or
project_name not in self.sync_module.get_enabled_projects()):
if (
sync_module is None
or not sync_module.enabled
or project_name not in sync_module.get_enabled_projects()
):
return mapping
active_site = self.sync_module.get_local_normalized_site(
self.sync_module.get_active_site(project_name))
remote_site = self.sync_module.get_local_normalized_site(
self.sync_module.get_remote_site(project_name))
active_site = sync_module.get_local_normalized_site(
sync_module.get_active_site(project_name))
remote_site = sync_module.get_local_normalized_site(
sync_module.get_remote_site(project_name))
self.log.debug(
"active {} - remote {}".format(active_site, remote_site)
)
if active_site == "local" and active_site != remote_site:
sync_settings = self.sync_module.get_sync_project_setting(
sync_settings = sync_module.get_sync_project_setting(
project_name,
exclude_locals=False,
cached=False)
@ -179,7 +190,7 @@ class HostDirmap(object):
self.log.debug("remote overrides {}".format(remote_overrides))
current_platform = platform.system().lower()
remote_provider = self.sync_module.get_provider_for_site(
remote_provider = sync_module.get_provider_for_site(
project_name, remote_site
)
# dirmap has sense only with regular disk provider, in the workfile

View file

@ -2955,6 +2955,7 @@ class DirmapCache:
"""Caching class to get settings and sync_module easily and only once."""
_project_name = None
_project_settings = None
_sync_module_discovered = False
_sync_module = None
_mapping = None
@ -2972,8 +2973,10 @@ class DirmapCache:
@classmethod
def sync_module(cls):
if cls._sync_module is None:
cls._sync_module = ModulesManager().modules_by_name["sync_server"]
if not cls._sync_module_discovered:
cls._sync_module_discovered = True
cls._sync_module = ModulesManager().modules_by_name.get(
"sync_server")
return cls._sync_module
@classmethod

View file

@ -34,7 +34,12 @@ from openpype.settings.constants import (
from .providers.local_drive import LocalDriveHandler
from .providers import lib
from .utils import time_function, SyncStatus, SiteAlreadyPresentError
from .utils import (
time_function,
SyncStatus,
SiteAlreadyPresentError,
SYNC_SERVER_ROOT,
)
log = Logger.get_logger("SyncServer")
@ -138,9 +143,23 @@ class SyncServerModule(OpenPypeModule, ITrayModule, IPluginPaths):
def get_plugin_paths(self):
"""Deadline plugin paths."""
current_dir = os.path.dirname(os.path.abspath(__file__))
return {
"load": [os.path.join(current_dir, "plugins", "load")]
"load": [os.path.join(SYNC_SERVER_ROOT, "plugins", "load")]
}
def get_site_icons(self):
"""Icons for sites.
Returns:
dict[str, str]: Path to icon by site.
"""
resource_path = os.path.join(
SYNC_SERVER_ROOT, "providers", "resources"
)
return {
provider: "{}/{}.png".format(resource_path, provider)
for provider in ["studio", "local_drive", "gdrive"]
}
""" Start of Public API """
@ -904,10 +923,7 @@ class SyncServerModule(OpenPypeModule, ITrayModule, IPluginPaths):
(str): full absolut path to directory with hooks for the module
"""
return os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"launch_hooks"
)
return os.path.join(SYNC_SERVER_ROOT, "launch_hooks")
# Needs to be refactored after Settings are updated
# # Methods for Settings to get appriate values to fill forms

View file

@ -1,9 +1,12 @@
import os
import time
from openpype.lib import Logger
log = Logger.get_logger("SyncServer")
SYNC_SERVER_ROOT = os.path.dirname(os.path.abspath(__file__))
class ResumableError(Exception):
"""Error which could be temporary, skip current loop, try next time"""

View file

@ -2,9 +2,10 @@ import os
import logging
import sys
import copy
import datetime
import clique
import six
from bson.objectid import ObjectId
import pyblish.api
@ -320,10 +321,16 @@ class IntegrateAsset(pyblish.api.InstancePlugin):
# Get the accessible sites for Site Sync
modules_by_name = instance.context.data["openPypeModules"]
sync_server_module = modules_by_name["sync_server"]
sites = sync_server_module.compute_resource_sync_sites(
project_name=instance.data["projectEntity"]["name"]
)
sync_server_module = modules_by_name.get("sync_server")
if sync_server_module is None:
sites = [{
"name": "studio",
"created_dt": datetime.datetime.now()
}]
else:
sites = sync_server_module.compute_resource_sync_sites(
project_name=instance.data["projectEntity"]["name"]
)
self.log.debug("Sync Server Sites: {}".format(sites))
# Compute the resource file infos once (files belonging to the

View file

@ -336,34 +336,6 @@ class PypeCommands:
import pytest
pytest.main(args)
def syncserver(self, active_site):
"""Start running sync_server in background.
This functionality is available in directly in module cli commands.
`~/openpype_console module sync_server syncservice`
"""
os.environ["OPENPYPE_LOCAL_ID"] = active_site
def signal_handler(sig, frame):
print("You pressed Ctrl+C. Process ended.")
sync_server_module.server_exit()
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
from openpype.modules import ModulesManager
manager = ModulesManager()
sync_server_module = manager.modules_by_name["sync_server"]
sync_server_module.server_init()
sync_server_module.server_start()
while True:
time.sleep(1.0)
def repack_version(self, directory):
"""Repacking OpenPype version."""
from openpype.tools.repack_version import VersionRepacker

View file

@ -114,9 +114,10 @@ class LibraryLoaderWindow(QtWidgets.QDialog):
manager = ModulesManager()
sync_server = manager.modules_by_name.get("sync_server")
sync_server_enabled = False
if sync_server is not None:
sync_server_enabled = sync_server.enabled
sync_server_enabled = (
sync_server is not None
and sync_server.enabled
)
repres_widget = None
if sync_server_enabled:

View file

@ -64,6 +64,7 @@ class BaseRepresentationModel(object):
"""Sets/Resets sync server vars after every change (refresh.)"""
repre_icons = {}
sync_server = None
sync_server_enabled = False
active_site = active_provider = None
remote_site = remote_provider = None
@ -75,6 +76,7 @@ class BaseRepresentationModel(object):
if not project_name:
self.repre_icons = repre_icons
self.sync_server = sync_server
self.sync_server_enabled = sync_server_enabled
self.active_site = active_site
self.active_provider = active_provider
self.remote_site = remote_site
@ -100,8 +102,13 @@ class BaseRepresentationModel(object):
self._modules_manager = ModulesManager()
self._last_manager_cache = now_time
sync_server = self._modules_manager.modules_by_name["sync_server"]
if sync_server.is_project_enabled(project_name, single=True):
sync_server = self._modules_manager.modules_by_name.get("sync_server")
if (
sync_server is not None
and sync_server.enabled
and sync_server.is_project_enabled(project_name, single=True)
):
sync_server_enabled = True
active_site = sync_server.get_active_site(project_name)
active_provider = sync_server.get_provider_for_site(
project_name, active_site)
@ -118,6 +125,7 @@ class BaseRepresentationModel(object):
self.repre_icons = repre_icons
self.sync_server = sync_server
self.sync_server_enabled = sync_server_enabled
self.active_site = active_site
self.active_provider = active_provider
self.remote_site = remote_site
@ -213,6 +221,7 @@ class SubsetsModel(BaseRepresentationModel, TreeModel):
self.repre_icons = {}
self.sync_server = None
self.sync_server_enabled = False
self.active_site = self.active_provider = None
self.columns_index = dict(
@ -282,7 +291,7 @@ class SubsetsModel(BaseRepresentationModel, TreeModel):
)
# update availability on active site when version changes
if self.sync_server.enabled and version_doc:
if self.sync_server_enabled and version_doc:
repres_info = list(
self.sync_server.get_repre_info_for_versions(
project_name,
@ -507,7 +516,7 @@ class SubsetsModel(BaseRepresentationModel, TreeModel):
return
repre_info_by_version_id = {}
if self.sync_server.enabled:
if self.sync_server_enabled:
versions_by_id = {}
for _subset_id, doc in last_versions_by_subset_id.items():
versions_by_id[doc["_id"]] = doc
@ -1033,12 +1042,16 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
self._version_ids = []
manager = ModulesManager()
sync_server = active_site = remote_site = None
active_site = remote_site = None
active_provider = remote_provider = None
sync_server = manager.modules_by_name.get("sync_server")
sync_server_enabled = (
sync_server is not None
and sync_server.enabled
)
project_name = dbcon.current_project()
if project_name:
sync_server = manager.modules_by_name["sync_server"]
if sync_server_enabled and project_name:
active_site = sync_server.get_active_site(project_name)
remote_site = sync_server.get_remote_site(project_name)
@ -1057,6 +1070,7 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
remote_provider = 'studio'
self.sync_server = sync_server
self.sync_server_enabled = sync_server_enabled
self.active_site = active_site
self.active_provider = active_provider
self.remote_site = remote_site
@ -1174,9 +1188,15 @@ class RepresentationModel(TreeModel, BaseRepresentationModel):
repre_groups_items[doc["name"]] = 0
group = group_item
progress = self.sync_server.get_progress_for_repre(
doc,
self.active_site, self.remote_site)
progress = {
self.active_site: 0,
self.remote_site: 0,
}
if self.sync_server_enabled:
progress = self.sync_server.get_progress_for_repre(
doc,
self.active_site,
self.remote_site)
active_site_icon = self._icons.get(self.active_provider)
remote_site_icon = self._icons.get(self.remote_provider)

View file

@ -1,9 +1,3 @@
import os
from openpype_modules import sync_server
from qtpy import QtGui
def walk_hierarchy(node):
"""Recursively yield group node."""
for child in node.children():
@ -12,19 +6,3 @@ def walk_hierarchy(node):
for _child in walk_hierarchy(child):
yield _child
def get_site_icons():
resource_path = os.path.join(
os.path.dirname(sync_server.sync_server_module.__file__),
"providers",
"resources"
)
icons = {}
# TODO get from sync module
for provider in ["studio", "local_drive", "gdrive"]:
pix_url = "{}/{}.png".format(resource_path, provider)
icons[provider] = QtGui.QIcon(pix_url)
return icons

View file

@ -24,10 +24,7 @@ from openpype.style import get_default_entity_icon_color
from openpype.tools.utils.models import TreeModel, Item
from openpype.modules import ModulesManager
from .lib import (
get_site_icons,
walk_hierarchy,
)
from .lib import walk_hierarchy
class InventoryModel(TreeModel):
@ -53,8 +50,10 @@ class InventoryModel(TreeModel):
self._default_icon_color = get_default_entity_icon_color()
manager = ModulesManager()
sync_server = manager.modules_by_name["sync_server"]
self.sync_enabled = sync_server.enabled
sync_server = manager.modules_by_name.get("sync_server")
self.sync_enabled = (
sync_server is not None and sync_server.enabled
)
self._site_icons = {}
self.active_site = self.remote_site = None
self.active_provider = self.remote_provider = None
@ -84,7 +83,10 @@ class InventoryModel(TreeModel):
self.active_provider = active_provider
self.remote_site = remote_site
self.remote_provider = remote_provider
self._site_icons = get_site_icons()
self._site_icons = {
provider: QtGui.QIcon(icon_path)
for provider, icon_path in self.get_site_icons().items()
}
if "active_site" not in self.Columns:
self.Columns.append("active_site")
if "remote_site" not in self.Columns:

View file

@ -54,8 +54,11 @@ class SceneInventoryView(QtWidgets.QTreeView):
self._selected = None
manager = ModulesManager()
self.sync_server = manager.modules_by_name["sync_server"]
self.sync_enabled = self.sync_server.enabled
sync_server = manager.modules_by_name.get("sync_server")
sync_enabled = sync_server is not None and self.sync_server.enabled
self.sync_server = sync_server
self.sync_enabled = sync_enabled
def _set_hierarchy_view(self, enabled):
if enabled == self._hierarchy_view:

View file

@ -267,19 +267,20 @@ class SitesWidget(QtWidgets.QWidget):
self.input_objects = {}
def _get_sites_inputs(self):
sync_server_module = (
self.modules_manager.modules_by_name["sync_server"]
)
output = []
if self._project_name is None:
return output
sync_server_module = self.modules_manager.modules_by_name.get(
"sync_server")
if sync_server_module is None or not sync_server_module.enabled:
return output
site_configs = sync_server_module.get_all_site_configs(
self._project_name, local_editable_only=True)
roots_entity = (
self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY]
)
site_names = [self.active_site_widget.current_text(),
self.remote_site_widget.current_text()]
output = []
for site_name in site_names:
if not site_name:
continue
@ -350,9 +351,6 @@ class SitesWidget(QtWidgets.QWidget):
def refresh(self):
self._clear_widgets()
if self._project_name is None:
return
# Site label
for site_name, site_inputs in self._get_sites_inputs():
site_widget = QtWidgets.QWidget(self.content_widget)

View file

@ -760,20 +760,23 @@ def create_qthread(func, *args, **kwargs):
def get_repre_icons():
"""Returns a dict {'provider_name': QIcon}"""
icons = {}
try:
from openpype_modules import sync_server
except Exception:
# Backwards compatibility
from openpype.modules import sync_server
try:
from openpype.modules import sync_server
except Exception:
return icons
resource_path = os.path.join(
os.path.dirname(sync_server.sync_server_module.__file__),
"providers", "resources"
)
icons = {}
if not os.path.exists(resource_path):
print("No icons for Site Sync found")
return {}
return icons
for file_name in os.listdir(resource_path):
if file_name and not file_name.endswith("png"):

View file

@ -203,8 +203,7 @@ def create_openpype_package(
ignored_modules = [
"ftrack",
"shotgrid",
# Sync server is still expected at multiple places
# "sync_server",
"sync_server",
"example_addons",
"slack"
]