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

Commit

Permalink
Merge pull request #6245 from ynput/feature/AY-742_copy-to-breakdown-…
Browse files Browse the repository at this point in the history
…project
  • Loading branch information
mkolar authored May 3, 2024
2 parents 407d879 + 7901009 commit da96c71
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 23 deletions.
5 changes: 5 additions & 0 deletions openpype/hosts/nuke/api/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
current_file
)
from .constants import ASSIST
from . import push_to_project

log = Logger.get_logger(__name__)

Expand Down Expand Up @@ -337,6 +338,10 @@ def _install_menu():
"Experimental tools...",
lambda: host_tools.show_experimental_tools_dialog(parent=main_window)
)
menu.addCommand(
"Push to Project",
lambda: push_to_project.main()
)
menu.addSeparator()
# add reload pipeline only in debug mode
if bool(os.getenv("NUKE_DEBUG")):
Expand Down
116 changes: 116 additions & 0 deletions openpype/hosts/nuke/api/push_to_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
from collections import defaultdict
import shutil
import os

from openpype.client import get_project, get_asset_by_id
from openpype.settings import get_system_settings, get_project_settings
from openpype.pipeline import Anatomy, registered_host
from openpype.pipeline.template_data import get_template_data
from openpype.pipeline.workfile import get_workdir_with_workdir_data
from openpype.tools.push_to_project.app import show

from .utils import bake_gizmos_recursively

import nuke


def bake_container(container):
"""Bake containers to read nodes."""

node = container["node"]

# Fetch knobs to remove in order.
knobs_to_remove = []
remove = False
for count in range(0, node.numKnobs()):
knob = node.knob(count)

# All knobs from "OpenPype" tab knob onwards.
if knob.name() == "OpenPype":
remove = True

if remove:
knobs_to_remove.append(knob)

# Dont remove knobs from "containerId" onwards.
if knob.name() == "containerId":
remove = False

# Knobs needs to be remove in reverse order, because child knobs needs to
# be remove first.
for knob in reversed(knobs_to_remove):
node.removeKnob(knob)

node["tile_color"].setValue(0)


def main():
context = show("", "", False, True)

if context is None:
return

# Get workfile path to save to.
project_name = context["project_name"]
project_doc = get_project(project_name)
asset_doc = get_asset_by_id(project_name, context["asset_id"])
task_name = context["task_name"]
host = registered_host()
system_settings = get_system_settings()
project_settings = get_project_settings(project_name)
anatomy = Anatomy(project_name)

workdir_data = get_template_data(
project_doc, asset_doc, task_name, host.name, system_settings
)

workdir = get_workdir_with_workdir_data(
workdir_data,
project_name,
anatomy,
project_settings=project_settings
)

# Save current workfile.
current_file = host.current_file()
host.save_file(current_file)

for container in host.ls():
bake_container(container)

# Bake gizmos.
bake_gizmos_recursively()

# Copy all read node files to "resources" folder next to workfile and
# change file path.
first_frame = int(nuke.root()["first_frame"].value())
last_frame = int(nuke.root()["last_frame"].value())
files_by_node_name = defaultdict(set)
nodes_by_name = {}
for count in range(first_frame, last_frame + 1):
nuke.frame(count)
for node in nuke.allNodes(filter="Read"):
files_by_node_name[node.name()].add(
nuke.filename(node, nuke.REPLACE)
)
nodes_by_name[node.name()] = node

resources_dir = os.path.join(workdir, "resources")
for name, files in files_by_node_name.items():
dir = os.path.join(resources_dir, name)
if not os.path.exists(dir):
os.makedirs(dir)

for f in files:
shutil.copy(f, os.path.join(dir, os.path.basename(f)))

node = nodes_by_name[name]
path = node["file"].value().replace(os.path.dirname(f), dir)
node["file"].setValue(path.replace("\\", "/"))

# Save current workfile to new context.
basename = os.path.basename(current_file)
host.save_file(os.path.join(workdir, basename))

# Open current contex workfile.
host.open_file(current_file)
26 changes: 18 additions & 8 deletions openpype/tools/push_to_project/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@
from openpype.tools.push_to_project.window import PushToContextSelectWindow


def show(project, version, library_filter, context_only):
window = PushToContextSelectWindow(
library_filter=library_filter, context_only=context_only
)
window.show()
window.controller.set_source(project, version)

if __name__ == "__main__":
app = get_openpype_qt_app()
app.exec_()
else:
window.exec_()

return window.context


@click.command()
@click.option("--project", help="Source project name")
@click.option("--version", help="Source version id")
Expand All @@ -13,15 +29,9 @@ def main(project, version):
Args:
project (str): Source project name.
version (str): Version id.
version (bool): Filter to library projects only.
"""

app = get_openpype_qt_app()

window = PushToContextSelectWindow()
window.show()
window.controller.set_source(project, version)

app.exec_()
show(project, version, True, False)


if __name__ == "__main__":
Expand Down
18 changes: 13 additions & 5 deletions openpype/tools/push_to_project/control_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,13 @@ def from_asset_doc(cls, asset_doc, project_doc):


class EntitiesModel:
def __init__(self, event_system):
def __init__(self, event_system, library_filter=True):
self._event_system = event_system
self._project_names = None
self._project_docs_by_name = {}
self._assets_by_project = {}
self._tasks_by_asset_id = collections.defaultdict(dict)
self.library_filter = library_filter

def has_cached_projects(self):
return self._project_names is None
Expand Down Expand Up @@ -135,7 +136,7 @@ def refresh_projects(self, force=False):
project_docs_by_name = {}
for project_doc in get_projects():
library_project = project_doc["data"].get("library_project")
if not library_project:
if not library_project and self.library_filter:
continue
project_name = project_doc["name"]
project_names.append(project_name)
Expand Down Expand Up @@ -366,15 +367,19 @@ def set_comment(self, comment):


class PushToContextController:
def __init__(self, project_name=None, version_id=None):
def __init__(
self, project_name=None, version_id=None, library_filter=True
):
self._src_project_name = None
self._src_version_id = None
self._src_asset_doc = None
self._src_subset_doc = None
self._src_version_doc = None

event_system = EventSystem()
entities_model = EntitiesModel(event_system)
entities_model = EntitiesModel(
event_system, library_filter=library_filter
)
selection_model = SelectionModel(event_system)
user_values = UserPublishValues(event_system)

Expand Down Expand Up @@ -629,13 +634,16 @@ def get_selected_asset_name(self):
return asset_item.name
return None

def submit(self, wait=True):
def submit(self, wait=True, context_only=False):
if not self.submission_enabled:
return

if self._process_thread is not None:
return

if context_only:
return

item = ProjectPushItem(
self.src_project_name,
self.src_version_id,
Expand Down
39 changes: 29 additions & 10 deletions openpype/tools/push_to_project/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,12 +367,16 @@ def _refresh(self, new_project_name):
self.items_changed.emit()


class PushToContextSelectWindow(QtWidgets.QWidget):
def __init__(self, controller=None):
class PushToContextSelectWindow(QtWidgets.QDialog):
def __init__(
self, controller=None, library_filter=True, context_only=False
):
super(PushToContextSelectWindow, self).__init__()
if controller is None:
controller = PushToContextController()
controller = PushToContextController(library_filter=library_filter)
self._controller = controller
self.context_only = context_only
self.context = None

self.setWindowTitle("Push to project (select context)")
self.setWindowIcon(QtGui.QIcon(get_app_icon_path()))
Expand Down Expand Up @@ -455,13 +459,13 @@ def __init__(self, controller=None):
# --- Buttons widget ---
btns_widget = QtWidgets.QWidget(self)
cancel_btn = QtWidgets.QPushButton("Cancel", btns_widget)
publish_btn = QtWidgets.QPushButton("Publish", btns_widget)
push_btn = QtWidgets.QPushButton("Push", btns_widget)

btns_layout = QtWidgets.QHBoxLayout(btns_widget)
btns_layout.setContentsMargins(0, 0, 0, 0)
btns_layout.addStretch(1)
btns_layout.addWidget(cancel_btn, 0)
btns_layout.addWidget(publish_btn, 0)
btns_layout.addWidget(push_btn, 0)

sep_1 = SeparatorWidget(parent=main_context_widget)
sep_2 = SeparatorWidget(parent=main_context_widget)
Expand Down Expand Up @@ -535,7 +539,7 @@ def __init__(self, controller=None):
self._on_task_change
)
task_model.items_changed.connect(self._on_task_model_change)
publish_btn.clicked.connect(self._on_select_click)
push_btn.clicked.connect(self._on_select_click)
cancel_btn.clicked.connect(self._on_close_click)
overlay_close_btn.clicked.connect(self._on_close_click)
overlay_try_btn.clicked.connect(self._on_try_again_click)
Expand Down Expand Up @@ -588,7 +592,7 @@ def __init__(self, controller=None):
self._asset_name_input = asset_name_input
self._comment_input = comment_input

self._publish_btn = publish_btn
self._push_btn = push_btn

self._overlay_widget = overlay_widget
self._overlay_close_btn = overlay_close_btn
Expand All @@ -612,7 +616,7 @@ def __init__(self, controller=None):
self._last_submit_message = None
self._process_item = None

publish_btn.setEnabled(False)
push_btn.setEnabled(False)
overlay_close_btn.setVisible(False)
overlay_try_btn.setVisible(False)

Expand Down Expand Up @@ -774,13 +778,28 @@ def _on_task_change(self):
self._controller.selection_model.select_task(task_name)

def _on_submission_change(self, event):
self._publish_btn.setEnabled(event["enabled"])
self._push_btn.setEnabled(event["enabled"])

def _on_close_click(self):
self.close()

def _on_select_click(self):
self._process_item = self._controller.submit(wait=False)
result = self._controller.submit(
wait=True, context_only=self.context_only
)

if self.context_only:
self.context = {
"project_name": self._controller.selection_model.project_name,
"asset_id": self._controller.selection_model.asset_id,
"task_name": self._controller.selection_model.task_name,
"variant": self._controller.user_values.variant,
"comment": self._controller.user_values.comment,
"asset_name": self._controller.user_values.new_asset_name
}
self.close()

self._process_item = result

def _on_try_again_click(self):
self._process_item = None
Expand Down

0 comments on commit da96c71

Please sign in to comment.