Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Webpublisher: Webpublisher is used as addon #3740

Merged
merged 17 commits into from
Aug 26, 2022
Merged
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
19 changes: 14 additions & 5 deletions openpype/hosts/aftereffects/api/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import contextlib
import traceback
import logging
from functools import partial

from Qt import QtWidgets

from openpype.pipeline import install_host
from openpype.lib.remote_publish import headless_publish
from openpype.modules import ModulesManager

from openpype.tools.utils import host_tools
from .launch_logic import ProcessLauncher, get_stub
Expand Down Expand Up @@ -35,10 +36,18 @@ def main(*subprocess_args):
launcher.start()

if os.environ.get("HEADLESS_PUBLISH"):
launcher.execute_in_main_thread(lambda: headless_publish(
log,
"CloseAE",
os.environ.get("IS_TEST")))
manager = ModulesManager()
webpublisher_addon = manager["webpublisher"]

launcher.execute_in_main_thread(
partial(
webpublisher_addon.headless_publish,
log,
"CloseAE",
os.environ.get("IS_TEST")
)
)

elif os.environ.get("AVALON_PHOTOSHOP_WORKFILES_ON_LAUNCH", True):
save = False
if os.getenv("WORKFILES_SAVE_AS"):
Expand Down
9 changes: 5 additions & 4 deletions openpype/hosts/photoshop/api/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@

from Qt import QtWidgets

from openpype.api import Logger
from openpype.lib import env_value_to_bool, Logger
from openpype.modules import ModulesManager
from openpype.pipeline import install_host
from openpype.tools.utils import host_tools
from openpype.lib.remote_publish import headless_publish
from openpype.lib import env_value_to_bool

from .launch_logic import ProcessLauncher, stub

Expand All @@ -35,8 +34,10 @@ def main(*subprocess_args):
launcher.start()

if env_value_to_bool("HEADLESS_PUBLISH"):
manager = ModulesManager()
webpublisher_addon = manager["webpublisher"]
launcher.execute_in_main_thread(
headless_publish,
webpublisher_addon.headless_publish,
log,
"ClosePS",
os.environ.get("IS_TEST")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@

import pyblish.api

from openpype.lib.plugin_tools import (
parse_json,
get_batch_asset_task_info
)
from openpype.pipeline import legacy_io
from openpype_modules.webpublisher.lib import (
get_batch_asset_task_info,
parse_json
)


class CollectBatchData(pyblish.api.ContextPlugin):
Expand Down
10 changes: 10 additions & 0 deletions openpype/hosts/webpublisher/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from .addon import (
WebpublisherAddon,
WEBPUBLISHER_ROOT_DIR,
)


__all__ = (
"WebpublisherAddon",
"WEBPUBLISHER_ROOT_DIR",
)
106 changes: 106 additions & 0 deletions openpype/hosts/webpublisher/addon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import os

import click

from openpype.modules import OpenPypeModule
from openpype.modules.interfaces import IHostModule

WEBPUBLISHER_ROOT_DIR = os.path.dirname(os.path.abspath(__file__))


class WebpublisherAddon(OpenPypeModule, IHostModule):
name = "webpublisher"
host_name = "webpublisher"

def initialize(self, module_settings):
self.enabled = True

def headless_publish(self, log, close_plugin_name=None, is_test=False):
"""Runs publish in a opened host with a context.

Close Python process at the end.
"""

from openpype.pipeline.publish.lib import remote_publish
from .lib import get_webpublish_conn, publish_and_log

if is_test:
remote_publish(log, close_plugin_name)
return

dbcon = get_webpublish_conn()
_id = os.environ.get("BATCH_LOG_ID")
if not _id:
log.warning("Unable to store log records, "
"batch will be unfinished!")
return

publish_and_log(
dbcon, _id, log, close_plugin_name=close_plugin_name
)

def cli(self, click_group):
click_group.add_command(cli_main)


@click.group(
WebpublisherAddon.name,
help="Webpublisher related commands.")
def cli_main():
pass


@cli_main.command()
@click.argument("path")
@click.option("-u", "--user", help="User email address")
@click.option("-p", "--project", help="Project")
@click.option("-t", "--targets", help="Targets", default=None,
multiple=True)
def publish(project, path, user=None, targets=None):
"""Start publishing (Inner command).

Publish collects json from paths provided as an argument.
More than one path is allowed.
"""

from .publish_functions import cli_publish

cli_publish(project, path, user, targets)


@cli_main.command()
@click.argument("path")
@click.option("-p", "--project", help="Project")
@click.option("-h", "--host", help="Host")
@click.option("-u", "--user", help="User email address")
@click.option("-t", "--targets", help="Targets", default=None,
multiple=True)
def publishfromapp(project, path, host, user=None, targets=None):
"""Start publishing through application (Inner command).

Publish collects json from paths provided as an argument.
More than one path is allowed.
"""

from .publish_functions import cli_publish_from_app

cli_publish_from_app(project, path, host, user, targets)


@cli_main.command()
@click.option("-e", "--executable", help="Executable")
@click.option("-u", "--upload_dir", help="Upload dir")
@click.option("-h", "--host", help="Host", default=None)
@click.option("-p", "--port", help="Port", default=None)
def webserver(executable, upload_dir, host=None, port=None):
"""Start service for communication with Webpublish Front end.

OP must be congigured on a machine, eg. OPENPYPE_MONGO filled AND
FTRACK_BOT_API_KEY provided with api key from Ftrack.

Expect "pype.club" user created on Ftrack.
"""

from .webserver_service import run_webserver

run_webserver(executable, upload_dir, host, port)
36 changes: 14 additions & 22 deletions openpype/hosts/webpublisher/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,23 @@
import os
import logging

from pyblish import api as pyblish
import openpype.hosts.webpublisher
from openpype.pipeline import legacy_io

log = logging.getLogger("openpype.hosts.webpublisher")

HOST_DIR = os.path.dirname(os.path.abspath(
openpype.hosts.webpublisher.__file__))
PLUGINS_DIR = os.path.join(HOST_DIR, "plugins")
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
import pyblish.api

from openpype.host import HostBase
from openpype.hosts.webpublisher import WEBPUBLISHER_ROOT_DIR

def install():
print("Installing Pype config...")

pyblish.register_plugin_path(PUBLISH_PATH)
log.info(PUBLISH_PATH)

legacy_io.install()
log = logging.getLogger("openpype.hosts.webpublisher")


def uninstall():
pyblish.deregister_plugin_path(PUBLISH_PATH)
class WebpublisherHost(HostBase):
name = "webpublisher"

def install(self):
print("Installing Pype config...")
pyblish.api.register_host(self.name)

# to have required methods for interface
def ls():
pass
publish_plugin_dir = os.path.join(
WEBPUBLISHER_ROOT_DIR, "plugins", "publish"
)
pyblish.api.register_plugin_path(publish_plugin_dir)
self.log.info(publish_plugin_dir)
100 changes: 46 additions & 54 deletions openpype/lib/remote_publish.py → openpype/hosts/webpublisher/lib.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import os
from datetime import datetime
import collections
import json

from bson.objectid import ObjectId

import pyblish.util
import pyblish.api

from openpype.client.mongo import OpenPypeMongoConnection
from openpype.lib.plugin_tools import parse_json
from openpype.settings import get_project_settings
from openpype.lib import Logger
from openpype.lib.profiles_filtering import filter_profiles
from openpype.api import get_project_settings
from openpype.pipeline.publish.lib import find_close_plugin

ERROR_STATUS = "error"
IN_PROGRESS_STATUS = "in_progress"
Expand All @@ -19,21 +21,51 @@
FINISHED_REPROCESS_STATUS = "republishing_finished"
FINISHED_OK_STATUS = "finished_ok"

log = Logger.get_logger(__name__)

def headless_publish(log, close_plugin_name=None, is_test=False):
"""Runs publish in a opened host with a context and closes Python process.

def parse_json(path):
"""Parses json file at 'path' location

Returns:
(dict) or None if unparsable
Raises:
AsssertionError if 'path' doesn't exist
"""
if not is_test:
dbcon = get_webpublish_conn()
_id = os.environ.get("BATCH_LOG_ID")
if not _id:
log.warning("Unable to store log records, "
"batch will be unfinished!")
return
path = path.strip('\"')
assert os.path.isfile(path), (
"Path to json file doesn't exist. \"{}\"".format(path)
)
data = None
with open(path, "r") as json_file:
try:
data = json.load(json_file)
except Exception as exc:
log.error(
"Error loading json: {} - Exception: {}".format(path, exc)
)
return data


def get_batch_asset_task_info(ctx):
"""Parses context data from webpublisher's batch metadata

publish_and_log(dbcon, _id, log, close_plugin_name=close_plugin_name)
Returns:
(tuple): asset, task_name (Optional), task_type
"""
task_type = "default_task_type"
task_name = None
asset = None

if ctx["type"] == "task":
items = ctx["path"].split('/')
asset = items[-2]
task_name = ctx["name"]
task_type = ctx["attributes"]["type"]
else:
publish(log, close_plugin_name)
asset = ctx["name"]

return asset, task_name, task_type


def get_webpublish_conn():
Expand Down Expand Up @@ -62,36 +94,6 @@ def start_webpublish_log(dbcon, batch_id, user):
}).inserted_id


def publish(log, close_plugin_name=None, raise_error=False):
"""Loops through all plugins, logs to console. Used for tests.

Args:
log (openpype.lib.Logger)
close_plugin_name (str): name of plugin with responsibility to
close host app
"""
# Error exit as soon as any error occurs.
error_format = "Failed {plugin.__name__}: {error} -- {error.traceback}"

close_plugin = _get_close_plugin(close_plugin_name, log)

for result in pyblish.util.publish_iter():
for record in result["records"]:
log.info("{}: {}".format(
result["plugin"].label, record.msg))

if result["error"]:
error_message = error_format.format(**result)
log.error(error_message)
if close_plugin: # close host app explicitly after error
context = pyblish.api.Context()
close_plugin().process(context)
if raise_error:
# Fatal Error is because of Deadline
error_message = "Fatal Error: " + error_format.format(**result)
raise RuntimeError(error_message)


def publish_and_log(dbcon, _id, log, close_plugin_name=None, batch_id=None):
"""Loops through all plugins, logs ok and fails into OP DB.

Expand All @@ -107,7 +109,7 @@ def publish_and_log(dbcon, _id, log, close_plugin_name=None, batch_id=None):
error_format = "Failed {plugin.__name__}: {error} -- {error.traceback}\n"
error_format += "-" * 80 + "\n"

close_plugin = _get_close_plugin(close_plugin_name, log)
close_plugin = find_close_plugin(close_plugin_name, log)

if isinstance(_id, str):
_id = ObjectId(_id)
Expand Down Expand Up @@ -226,16 +228,6 @@ def find_variant_key(application_manager, host):
return found_variant_key


def _get_close_plugin(close_plugin_name, log):
if close_plugin_name:
plugins = pyblish.api.discover()
for plugin in plugins:
if plugin.__name__ == close_plugin_name:
return plugin

log.debug("Close plugin not found, app might not close.")


def get_task_data(batch_dir):
"""Return parsed data from first task manifest.json

Expand Down
Loading