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

Nuke: simplified deadline submission on write node - AY-974 #314

Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c6d72a6
Add render farm button on write nodes.
tokejepsen Mar 28, 2024
eca60b0
Review feedback
tokejepsen Apr 5, 2024
8514005
Code cosmetics
tokejepsen Apr 12, 2024
cd45e9a
docstring
tokejepsen Apr 12, 2024
4f70d30
docstring
tokejepsen Apr 12, 2024
756e1f9
Deactivate workfile instance.
tokejepsen Apr 12, 2024
4fcab3c
Remove redundant code.
tokejepsen Apr 15, 2024
b6a5ead
Update client/ayon_core/hosts/nuke/api/lib.py
tokejepsen Apr 15, 2024
acacf15
Code cosmetics
tokejepsen Apr 30, 2024
0462d38
Use pyblish plugins instead of code outside of publishing.
tokejepsen May 2, 2024
157ff08
Merge branch 'develop' into enhancement/AY-974_Nuke-simplified-deadli…
tokejepsen May 2, 2024
81c7584
increment nuke package
tokejepsen May 2, 2024
a3c2bb1
Show successfull message.
tokejepsen May 2, 2024
e5fbb20
Skip script version increment
tokejepsen May 2, 2024
ce13e86
Full imports
tokejepsen May 3, 2024
8a971f3
CollectHeadlessFarm > ContextPlugin
tokejepsen May 7, 2024
978e7d1
Update client/ayon_core/hosts/nuke/api/lib.py
tokejepsen May 7, 2024
e9dc1d4
Update client/ayon_core/hosts/nuke/plugins/publish/collect_headless_f…
tokejepsen May 7, 2024
72116cd
Update client/ayon_core/hosts/nuke/api/utils.py
tokejepsen May 7, 2024
5b591b6
Ensure CreateInstance is active.
tokejepsen May 7, 2024
54500db
Update client/ayon_core/hosts/nuke/plugins/publish/collect_headless_f…
tokejepsen May 7, 2024
fd71818
Remove redundant code
tokejepsen May 7, 2024
d8eb451
Illicit feedback
tokejepsen May 7, 2024
ad7d24c
Disable instances as early as possible.
tokejepsen May 7, 2024
c752e35
Merge branch 'develop' into enhancement/AY-974_Nuke-simplified-deadli…
jakubjezek001 May 8, 2024
818aaf9
Merge branch 'develop' into enhancement/AY-974_Nuke-simplified-deadli…
jakubjezek001 May 17, 2024
8c4a79c
Merge branch 'develop' into enhancement/AY-974_Nuke-simplified-deadli…
tokejepsen May 21, 2024
8f4334f
Merge branch 'develop' into enhancement/AY-974_Nuke-simplified-deadli…
jakubjezek001 May 22, 2024
a75cb56
Update client/ayon_core/hosts/nuke/plugins/publish/collect_headless_f…
tokejepsen May 23, 2024
459e9a5
Update client/ayon_core/hosts/nuke/api/lib.py
tokejepsen May 23, 2024
3debb92
Use publish_attributes
tokejepsen May 23, 2024
4c6eb7a
Revert use_published_workfile
tokejepsen May 23, 2024
23ee1ca
Update client/ayon_core/hosts/nuke/plugins/publish/collect_headless_f…
tokejepsen May 23, 2024
3dfe367
Change to Render On Farm
tokejepsen May 23, 2024
8eb5c2a
Merge branch 'develop' into enhancement/AY-974_Nuke-simplified-deadli…
tokejepsen May 23, 2024
da4da46
Blacklisting plugins for workfile version validation and incrementing
jakubjezek001 May 24, 2024
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
25 changes: 25 additions & 0 deletions client/ayon_core/hosts/nuke/api/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,16 @@ def script_name():
return nuke.root().knob("name").value()


def add_button_headless_farm_submission(node):
name = "headlessFarmSubmission"
label = "Headless Farm Submission"
value = "from ayon_core.hosts.nuke.api.utils import submit_headless_farm;"
value += "submit_headless_farm(nuke.thisNode())"
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
knob = nuke.PyScript_Knob(name, label, value)
knob.clearFlag(nuke.STARTLINE)
node.addKnob(knob)


def add_button_write_to_read(node):
name = "createReadNode"
label = "Read From Rendered"
Expand Down Expand Up @@ -1144,6 +1154,17 @@ def create_write_node(
Return:
node (obj): group node with avalon data as Knobs
'''
# Ensure name does not contain any invalid characters.
special_chars = re.escape("!@#$%^&*()=[]{}|\\;',.<>/?~+-")
special_chars_regex = re.compile(f"[{special_chars}]")
found_special_characters = list(special_chars_regex.findall(name))

msg = (
f"Special characters found in name \"{name}\": "
f"{' '.join(found_special_characters)}"
)
assert not found_special_characters, msg

prenodes = prenodes or []

# filtering variables
Expand Down Expand Up @@ -1268,6 +1289,10 @@ def create_write_node(
link.setFlag(0x1000)
GN.addKnob(link)

# Adding render farm submission button.
if data.get("headless_farm_submission", False):
add_button_headless_farm_submission(GN)

# adding write to read button
add_button_write_to_read(GN)

Expand Down
92 changes: 91 additions & 1 deletion client/ayon_core/hosts/nuke/api/utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import os
import re
import traceback

import nuke

from ayon_core import resources
import pyblish.util
import pyblish.api
from qtpy import QtWidgets

from ayon_core import resources
from ayon_core.pipeline import registered_host
from ayon_core.tools.utils import show_message_dialog
from ayon_core.pipeline.create import CreateContext


def set_context_favorites(favorites=None):
""" Adding favorite folders to nuke's browser
Expand Down Expand Up @@ -142,3 +149,86 @@ def is_headless():
bool: headless
"""
return QtWidgets.QApplication.instance() is None


def create_error_report(context):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's too bad this is in nuke.api.utils - this is really something that should be "easy" to retrieve from the publishing API and should not need a 'nuke specific implementation' I would say.

Anyway, docstring would be welcome.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be at least renamed to create_publish_error_report?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👆

"""Create an error report based on the given pyblish context.

This function iterates through the results in the context and formats any
errors into a comprehensive error report.

Args:
context (dict): Pyblish context.

Returns:
tuple: A tuple containing a boolean indicating success and a string
representing the error message.
"""

error_message = ""
success = True
for result in context.data["results"]:
if result["success"]:
continue

success = False

err = result["error"]
error_message += "\n"
error_message += err.formatted_traceback

return success, error_message


def submit_headless_farm(node):
# Ensure code is executed in root context.
if nuke.root() == nuke.thisNode():
_submit_headless_farm(node)
else:
# If not in root context, move to the root context and then execute the
# code.
with nuke.root():
_submit_headless_farm(node)


def _submit_headless_farm(node):
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
"""Headless farm submission

This function prepares the context for farm submission, validates it,
extracts relevant data, copies the current workfile to a timestamped copy,
and submits the job to the farm.

Args:
node (Node): The node for which the farm submission is being made.
"""

host = registered_host()
create_context = CreateContext(host)

# Ensure CreateInstance is enabled.
for instance in create_context.instances:
if node.name() != instance.transient_data["node"].name():
continue

instance.data["active"] = True

context = pyblish.api.Context()
context.data["create_context"] = create_context
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
# Used in pyblish plugin to determine which instance to publish.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it very confusing that throughout the code you keep mentioning "publish". This workflow is not doing any publish right? It's only doing a Nuke render in the farm?

context.data["node_name"] = node.name()
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
# Used in pyblish plugins to determine whether to run or not.
context.data["headless_farm"] = True

context = pyblish.util.publish(context)

success, error_report = create_error_report(context)

if not success:
show_message_dialog(
"Collection Errors", error_report, level="critical"
)
return

show_message_dialog(
"Submission Successful", "Submission to the farm was successful."
)
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@ def _get_frame_source_number(self):
)

def create_instance_node(self, product_name, instance_data):
settings = self.project_settings["nuke"]["create"]["CreateWriteImage"]
settings = settings["instance_attributes"]

# add fpath_template
write_data = {
"creator": self.__class__.__name__,
"productName": product_name,
"fpath_template": self.temp_rendering_path_template
"fpath_template": self.temp_rendering_path_template,
"headless_farm_submission": "headless_farm_submission" in settings
}
write_data.update(instance_data)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,15 @@ def get_pre_create_attr_defs(self):
return attr_defs

def create_instance_node(self, product_name, instance_data):
settings = self.project_settings["nuke"]["create"]
settings = settings["CreateWritePrerender"]["instance_attributes"]

# add fpath_template
write_data = {
"creator": self.__class__.__name__,
"productName": product_name,
"fpath_template": self.temp_rendering_path_template
"fpath_template": self.temp_rendering_path_template,
"headless_farm_submission": "headless_farm_submission" in settings
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
}

write_data.update(instance_data)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,17 @@ def get_pre_create_attr_defs(self):
return attr_defs

def create_instance_node(self, product_name, instance_data):
settings = self.project_settings["nuke"]["create"]["CreateWriteRender"]
instance_attributes = settings["instance_attributes"]

# add fpath_template
write_data = {
"creator": self.__class__.__name__,
"productName": product_name,
"fpath_template": self.temp_rendering_path_template
"fpath_template": self.temp_rendering_path_template,
"headless_farm_submission": (
"headless_farm_submission" in instance_attributes
)
}

write_data.update(instance_data)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import pyblish.api


class CollectHeadlessFarm(pyblish.api.ContextPlugin):
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
"""Setup instances for headless farm submission."""

# Needs to be after CollectFromCreateContext
order = pyblish.api.CollectorOrder - 0.4
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
label = "Collect Headless Farm"
hosts = ["nuke"]

def process(self, context):
if not context.data.get("headless_farm", False):
return

for instance in context:
if instance.data["family"] == "workfile":
instance.data["active"] = False
continue

# Filter out all other instances.
node = instance.data["transientData"]["node"]
if node.name() != instance.context.data["node_name"]:
instance.data["active"] = False
continue

instance.data["families"].append("headless_farm")


class SetupHeadlessFarm(pyblish.api.InstancePlugin):
"""Setup instance for headless farm submission."""

order = pyblish.api.CollectorOrder + 0.4999
label = "Setup Headless Farm"
hosts = ["nuke"]
families = ["headless_farm"]

def process(self, instance):
# Enable for farm publishing.
instance.data["farm"] = True

# Clear the families as we only want the main family, ei. no review
# etc.
instance.data["families"] = ["headless_farm"]

# Use the workfile instead of published.
instance.data["use_published_workfile"] = False
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import os
from datetime import datetime
import shutil

import pyblish.api

from ayon_core.pipeline import registered_host


class ExtractHeadlessFarm(pyblish.api.InstancePlugin):
"""Copy the workfile to a timestamped copy."""

order = pyblish.api.ExtractorOrder + 0.499
label = "Extract Headless Farm"
hosts = ["nuke"]
families = ["headless_farm"]

def process(self, instance):
if not instance.context.data.get("headless_farm", False):
return

host = registered_host()
current_datetime = datetime.now()
formatted_timestamp = current_datetime.strftime("%Y%m%d%H%M%S")
base, ext = os.path.splitext(host.current_file())

directory = os.path.join(os.path.dirname(base), "farm_submissions")
if not os.path.exists(directory):
os.makedirs(directory)

filename = "{}_{}{}".format(
os.path.basename(base), formatted_timestamp, ext
)
path = os.path.join(directory, filename).replace("\\", "/")
instance.context.data["currentFile"] = path
shutil.copy(host.current_file(), path)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class IncrementScriptVersion(pyblish.api.ContextPlugin):
hosts = ['nuke']

def process(self, context):
if context.data.get("headless_farm", False):
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
return

assert all(result["success"] for result in context.data["results"]), (
"Publishing not successful so version is not increased.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,11 @@ def process(self, instance):
render_path = instance.data['path']
script_path = context.data["currentFile"]

use_published_workfile = instance.data["attributeValues"].get(
"use_published_workfile", self.use_published_workfile
use_published_workfile = instance.data.get(
tokejepsen marked this conversation as resolved.
Show resolved Hide resolved
"use_published_workfile",
instance.data["attributeValues"].get(
"use_published_workfile", self.use_published_workfile
)
)
if use_published_workfile:
script_path = self._get_published_workfile_path(context)
Expand Down
9 changes: 7 additions & 2 deletions client/ayon_core/plugins/publish/validate_version.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pyblish.api
from ayon_core.pipeline.publish import PublishValidationError
from ayon_core.pipeline.publish import (
PublishValidationError, OptionalPyblishPluginMixin
)


class ValidateVersion(pyblish.api.InstancePlugin):
class ValidateVersion(pyblish.api.InstancePlugin, OptionalPyblishPluginMixin):
"""Validate instance version.

AYON does not allow overwriting previously published versions.
Expand All @@ -18,6 +20,9 @@ class ValidateVersion(pyblish.api.InstancePlugin):
active = True

def process(self, instance):
if not self.is_active(instance.data):
return

version = instance.data.get("version")
latest_version = instance.data.get("latestVersion")

Expand Down
2 changes: 1 addition & 1 deletion server_addon/nuke/package.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
name = "nuke"
title = "Nuke"
version = "0.1.11"
version = "0.1.12"
6 changes: 5 additions & 1 deletion server_addon/nuke/server/settings/create_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ def instance_attributes_enum():
return [
{"value": "reviewable", "label": "Reviewable"},
{"value": "farm_rendering", "label": "Farm rendering"},
{"value": "use_range_limit", "label": "Use range limit"}
{"value": "use_range_limit", "label": "Use range limit"},
{
"value": "headless_farm_submission",
"label": "Headless Farm Submission"
}
]


Expand Down
Loading