From 357dfa3b1f76f0cadafc5e3b178573f45752cc2c Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 1 Mar 2021 19:11:46 +0100 Subject: [PATCH] Deadline Pype 3 - added PYPE_RENDER_JOB Used to differentiate between render and publish job for event handling --- vendor/deadline/custom/events/Pype/Pype.py | 19 +-- .../deadline/custom/plugins/Pype/Pype.param | 37 ++++++ vendor/deadline/custom/plugins/Pype/Pype.py | 112 ++++++++++++++++++ 3 files changed, 160 insertions(+), 8 deletions(-) create mode 100644 vendor/deadline/custom/plugins/Pype/Pype.param create mode 100644 vendor/deadline/custom/plugins/Pype/Pype.py diff --git a/vendor/deadline/custom/events/Pype/Pype.py b/vendor/deadline/custom/events/Pype/Pype.py index e79358b1e5..a7043d8070 100644 --- a/vendor/deadline/custom/events/Pype/Pype.py +++ b/vendor/deadline/custom/events/Pype/Pype.py @@ -111,7 +111,8 @@ class PypeEventListener(Deadline.Events.DeadlineEventListener): if pype_publish_job == '1' and pype_render_job == '1': raise RuntimeError("Misconfiguration. Job couldn't be both " + "render and publish.") - elif pype_publish_job == '1': + + if pype_publish_job == '1': self.LogInfo("Publish job, skipping inject.") return elif pype_render_job == '0': @@ -162,7 +163,7 @@ class PypeEventListener(Deadline.Events.DeadlineEventListener): exit_code = subprocess.call(args, shell=True) if exit_code != 0: - raise RuntimeError("Publishing failed") + raise RuntimeError("Publishing failed, check worker's log") with open(export_url) as fp: contents = json.load(fp) @@ -221,7 +222,7 @@ class PypeEventListener(Deadline.Events.DeadlineEventListener): self.updateFtrackStatus(job, "Rendering") def OnJobFinished(self, job): - self.LogInfo("OnJobFinished") + #self.LogInfo("OnJobFinished") self.updateFtrackStatus(job, "Artist Review") def OnJobRequeued(self, job): @@ -249,8 +250,8 @@ class PypeEventListener(Deadline.Events.DeadlineEventListener): pass def OnJobError(self, job, task, report): - self.LogInfo("OnJobError LOGGING") - # data = {"task": task, "report": report} + #self.LogInfo("OnJobError LOGGING") + pass def OnJobPurged(self, job): pass @@ -258,11 +259,12 @@ class PypeEventListener(Deadline.Events.DeadlineEventListener): def OnHouseCleaning(self): pass - def OnRepositoryRepair(self, job): + def OnRepositoryRepair(self, job, *args): pass def OnSlaveStarted(self, job): - self.LogInfo("OnSlaveStarted LOGGING") + #self.LogInfo("OnSlaveStarted LOGGING") + pass def OnSlaveStopped(self, job): pass @@ -271,7 +273,8 @@ class PypeEventListener(Deadline.Events.DeadlineEventListener): pass def OnSlaveRendering(self, host_name, job): - self.LogInfo("OnSlaveRendering LOGGING") + #self.LogInfo("OnSlaveRendering LOGGING") + pass def OnSlaveStartingJob(self, host_name, job): self.LogInfo("OnSlaveStartingJob LOGGING") diff --git a/vendor/deadline/custom/plugins/Pype/Pype.param b/vendor/deadline/custom/plugins/Pype/Pype.param new file mode 100644 index 0000000000..1452163bdd --- /dev/null +++ b/vendor/deadline/custom/plugins/Pype/Pype.param @@ -0,0 +1,37 @@ +[State] +Type=Enum +Items=Global Enabled;Opt-In;Disabled +Category=Options +CategoryOrder=0 +CategoryIndex=0 +Label=State +Default=Global Enabled +Description=How this event plug-in should respond to events. If Global, all jobs and slaves will trigger the events for this plugin. If Opt-In, jobs and slaves can choose to trigger the events for this plugin. If Disabled, no events are triggered for this plugin. + +[PythonSearchPaths] +Type=MultiLineMultiFolder +Label=Additional Python Search Paths +Category=Options +CategoryOrder=0 +CategoryIndex=1 +Default= +Description=The list of paths to append to the PYTHONPATH environment variable. This allows the Python job to find custom modules in non-standard locations. + +[LoggingLevel] +Type=Enum +Label=Logging Level +Category=Options +CategoryOrder=0 +CategoryIndex=2 +Items=DEBUG;INFO;WARNING;ERROR +Default=DEBUG +Description=Logging level where printing will start. + +[PypeExecutable] +Type=MultiLineMultiFolder +Label=Path to Pype executable dir +Category=Job Plugins +CategoryOrder=1 +CategoryIndex=1 +Default= +Description= \ No newline at end of file diff --git a/vendor/deadline/custom/plugins/Pype/Pype.py b/vendor/deadline/custom/plugins/Pype/Pype.py new file mode 100644 index 0000000000..7465ff6854 --- /dev/null +++ b/vendor/deadline/custom/plugins/Pype/Pype.py @@ -0,0 +1,112 @@ +import sys +import subprocess +import platform +import os + +from Deadline.Plugins import DeadlinePlugin, PluginType + + +###################################################################### +## This is the function that Deadline calls to get an instance of the +## main DeadlinePlugin class. +###################################################################### +def GetDeadlinePlugin(): + return PypeDeadlinePlugin() + + +def CleanupDeadlinePlugin(deadlinePlugin): + deadlinePlugin.Cleanup() + + + +class PypeDeadlinePlugin(DeadlinePlugin): + """ + Standalone plugin for publishing from Pype. + + Calls Pype executable 'pype_console' from first correctly found + file based on plugin configuration. Uses 'publish' command and passes + path to metadata json file, which contains all needed information + for publish process. + """ + def __init__(self): + self.StartJobCallback += self.StartJob + self.InitializeProcessCallback += self.InitializeProcess + self.RenderTasksCallback += self.RenderTasks + + def Cleanup(self): + del self.StartJobCallback + del self.InitializeProcessCallback + del self.RenderTasksCallback + + def StartJob(self): + # adding python search paths + paths = self.GetConfigEntryWithDefault("PythonSearchPaths", "").strip() + paths = paths.split(";") + + for path in paths: + self.LogInfo("Extending sys.path with: " + str(path)) + sys.path.append(path) + + self.LogInfo("PypeDeadlinePlugin start") + try: + metadata_file = \ + self.GetProcessEnvironmentVariable("PYPE_METADATA_FILE") + if not metadata_file: + raise RuntimeError("Env var PYPE_METADATA_FILE value missing") + + pype_app = self.get_pype_executable_path() + + args = [ + pype_app, + 'publish', + metadata_file + ] + + env = {} + env = dict(os.environ) + + job = self.GetJob() + for key in job.GetJobEnvironmentKeys(): + env[str(key)] = str(job.GetJobEnvironmentKeyValue(key)) + + exit_code = subprocess.call(args, shell=True, env=env) + if exit_code != 0: + raise RuntimeError("Publishing failed, check worker's log") + + self.LogInfo("PypeDeadlinePlugin end") + except Exception: + import traceback + self.LogInfo(traceback.format_exc()) + self.LogInfo("PypeDeadlinePlugin failed") + raise + + ## Called by Deadline to initialize the process. + def InitializeProcess(self): + # Set the plugin specific settings. + self.PluginType = PluginType.Simple + + def RenderTasks(self): + # do nothing, no render, just publishing, still must be here + pass + + def get_pype_executable_path(self): + """ + Returns calculated path based on settings and platform + + Uses 'pype_console' executable + """ + pype_command = "pype_console" + if platform.system().lower() == "linux": + pype_command = "pype_console.sh" + if platform.system().lower() == "windows": + pype_command = "pype_console.exe" + + pype_root = self.GetConfigEntryWithDefault("PypeExecutable", "") + + pype_app = os.path.join(pype_root.strip(), pype_command) + if not os.path.exists(pype_app): + raise RuntimeError("App '{}' doesn't exist. " + + "Fix it in Tools > Configure Events > " + + "pype".format(pype_app)) + + return pype_app