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

Commit

Permalink
Initial working version
Browse files Browse the repository at this point in the history
  • Loading branch information
tokejepsen committed Mar 18, 2024
1 parent ef33105 commit 2d7bc88
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 17 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
128 changes: 128 additions & 0 deletions openpype/hosts/nuke/api/push_to_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
from collections import defaultdict
import shutil
import os
import json
import re

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 import PACKAGE_DIR
from openpype.lib import get_openpype_execute_args, run_subprocess

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():
# Get project name, asset id and task name.
push_tool_script_path = os.path.join(
PACKAGE_DIR,
"tools",
"push_to_project",
"app.py"
)

args = get_openpype_execute_args(
"run",
push_tool_script_path,
"--library_filter", "False",
"--context_only", "True"
)
output = run_subprocess(args)
dict_string = re.search(r'\{.*\}', output).group()
result = json.loads(dict_string)

# Get workfile path to save to.
project_name = result["project_name"]
project_doc = get_project(project_name)
asset_doc = get_asset_by_id(project_name, result["asset_id"])
task_name = result["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
)

# Warn about saving current workfile.
# Save current workfile.
current_file = host.current_file()
host.save_file(current_file)

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

# 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)
24 changes: 21 additions & 3 deletions openpype/tools/push_to_project/app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json

import click

from openpype.tools.utils import get_openpype_qt_app
Expand All @@ -7,22 +9,38 @@
@click.command()
@click.option("--project", help="Source project name")
@click.option("--version", help="Source version id")
def main(project, version):
@click.option("--library_filter", help="Filter to library projects only.")
@click.option("--context_only", help="Return new context only.")
def main(project, version, library_filter, context_only):
"""Run PushToProject tool to integrate version in different project.
Args:
project (str): Source project name.
version (str): Version id.
version (bool): Filter to library projects only.
"""

app = get_openpype_qt_app()

window = PushToContextSelectWindow()
if library_filter is None:
library_filter = True
else:
library_filter = library_filter == "True"

if context_only is None:
context_only = True
else:
context_only = context_only == "True"

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

app.exec_()

print(json.dumps(window.context))


if __name__ == "__main__":
main()
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
36 changes: 27 additions & 9 deletions openpype/tools/push_to_project/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,14 @@ def _refresh(self, new_project_name):


class PushToContextSelectWindow(QtWidgets.QWidget):
def __init__(self, controller=None):
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.setWindowTitle("Push to project (select context)")
self.setWindowIcon(QtGui.QIcon(get_app_icon_path()))
Expand Down Expand Up @@ -455,13 +458,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 +538,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 +591,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 +615,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 +777,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 2d7bc88

Please sign in to comment.