diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 86a1d92..9886903 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -109,12 +109,12 @@ You can run the adaptor on your local workstation. This approach does not contai ```bash # Path mapping disabled - NukeAdaptor run --init-data file://init-data.yaml --run-data file://run-data.yaml + nuke-openjd run --init-data file://init-data.yaml --run-data file://run-data.yaml #path mapping enabled - NukeAdaptor run --init-data file://init-data.yaml --run-data file://run-data.yaml --path-mapping-rules file://path-mapping.yaml + nuke-openjd run --init-data file://init-data.yaml --run-data file://run-data.yaml --path-mapping-rules file://path-mapping.yaml ``` - NOTE: The NukeAdaptor expects that the Nuke executable is named `nuke` and is set on the PATH. If this is not the case, you can set the `NUKE_ADAPTOR_NUKE_EXECUTABLE` environment variable to the path to the Nuke executable. + NOTE: The nuke-openjd binary expects that the Nuke executable is named `nuke` and is set on the PATH. If this is not the case, you can set the `NUKE_ADAPTOR_NUKE_EXECUTABLE` environment variable to the path to the Nuke executable. 4. The result will be written based on the output specified on the write node, taking any path mapping into account. diff --git a/job_bundle_output_tests/cwd-path/expected_job_bundle/parameter_values.yaml b/job_bundle_output_tests/cwd-path/expected_job_bundle/parameter_values.yaml index 0d336cc..c371963 100644 --- a/job_bundle_output_tests/cwd-path/expected_job_bundle/parameter_values.yaml +++ b/job_bundle_output_tests/cwd-path/expected_job_bundle/parameter_values.yaml @@ -5,8 +5,6 @@ parameterValues: value: /normalized/job/bundle/dir/cwd-path.nk - name: ProxyMode value: 'false' -- name: TelemetryOptOut - value: 'false' - name: deadline:targetTaskRunStatus value: READY - name: deadline:maxFailedTasksCount diff --git a/job_bundle_output_tests/cwd-path/expected_job_bundle/template.yaml b/job_bundle_output_tests/cwd-path/expected_job_bundle/template.yaml index 39e303c..502fd4b 100644 --- a/job_bundle_output_tests/cwd-path/expected_job_bundle/template.yaml +++ b/job_bundle_output_tests/cwd-path/expected_job_bundle/template.yaml @@ -59,12 +59,6 @@ parameterDefinitions: allowedValues: - 'true' - 'false' -- name: TelemetryOptOut - type: STRING - default: 'false' - allowedValues: - - 'true' - - 'false' steps: - name: Render parameterSpace: @@ -84,7 +78,6 @@ steps: continue_on_error: {{Param.ContinueOnError}} proxy: {{Param.ProxyMode}} script_file: '{{Param.NukeScriptFile}}' - telemetry_opt_out: {{Param.TelemetryOptOut}} write_nodes: - '{{Param.WriteNode}}' views: diff --git a/job_bundle_output_tests/group-read/expected_job_bundle/parameter_values.yaml b/job_bundle_output_tests/group-read/expected_job_bundle/parameter_values.yaml index 7ecee9d..fbb6c1e 100644 --- a/job_bundle_output_tests/group-read/expected_job_bundle/parameter_values.yaml +++ b/job_bundle_output_tests/group-read/expected_job_bundle/parameter_values.yaml @@ -5,8 +5,6 @@ parameterValues: value: /normalized/job/bundle/dir/group-read.nk - name: ProxyMode value: 'false' -- name: TelemetryOptOut - value: 'false' - name: deadline:targetTaskRunStatus value: READY - name: deadline:maxFailedTasksCount diff --git a/job_bundle_output_tests/group-read/expected_job_bundle/template.yaml b/job_bundle_output_tests/group-read/expected_job_bundle/template.yaml index a38580e..722e5ab 100644 --- a/job_bundle_output_tests/group-read/expected_job_bundle/template.yaml +++ b/job_bundle_output_tests/group-read/expected_job_bundle/template.yaml @@ -58,12 +58,6 @@ parameterDefinitions: allowedValues: - 'true' - 'false' -- name: TelemetryOptOut - type: STRING - default: 'false' - allowedValues: - - 'true' - - 'false' steps: - name: Render parameterSpace: @@ -83,7 +77,6 @@ steps: continue_on_error: {{Param.ContinueOnError}} proxy: {{Param.ProxyMode}} script_file: '{{Param.NukeScriptFile}}' - telemetry_opt_out: {{Param.TelemetryOptOut}} write_nodes: - '{{Param.WriteNode}}' views: diff --git a/job_bundle_output_tests/multi-load-save/expected_job_bundle/parameter_values.yaml b/job_bundle_output_tests/multi-load-save/expected_job_bundle/parameter_values.yaml index 0032489..474d32f 100644 --- a/job_bundle_output_tests/multi-load-save/expected_job_bundle/parameter_values.yaml +++ b/job_bundle_output_tests/multi-load-save/expected_job_bundle/parameter_values.yaml @@ -5,8 +5,6 @@ parameterValues: value: /normalized/job/bundle/dir/multi-load-save.nk - name: ProxyMode value: 'false' -- name: TelemetryOptOut - value: 'false' - name: deadline:targetTaskRunStatus value: READY - name: deadline:maxFailedTasksCount diff --git a/job_bundle_output_tests/multi-load-save/expected_job_bundle/template.yaml b/job_bundle_output_tests/multi-load-save/expected_job_bundle/template.yaml index 76bafdd..62f2472 100644 --- a/job_bundle_output_tests/multi-load-save/expected_job_bundle/template.yaml +++ b/job_bundle_output_tests/multi-load-save/expected_job_bundle/template.yaml @@ -61,12 +61,6 @@ parameterDefinitions: allowedValues: - 'true' - 'false' -- name: TelemetryOptOut - type: STRING - default: 'false' - allowedValues: - - 'true' - - 'false' steps: - name: Render parameterSpace: @@ -86,7 +80,6 @@ steps: continue_on_error: {{Param.ContinueOnError}} proxy: {{Param.ProxyMode}} script_file: '{{Param.NukeScriptFile}}' - telemetry_opt_out: {{Param.TelemetryOptOut}} write_nodes: - '{{Param.WriteNode}}' views: diff --git a/job_bundle_output_tests/noise-saver/expected_job_bundle/parameter_values.yaml b/job_bundle_output_tests/noise-saver/expected_job_bundle/parameter_values.yaml index 215f862..6484d6b 100644 --- a/job_bundle_output_tests/noise-saver/expected_job_bundle/parameter_values.yaml +++ b/job_bundle_output_tests/noise-saver/expected_job_bundle/parameter_values.yaml @@ -5,8 +5,6 @@ parameterValues: value: /normalized/job/bundle/dir/noise-saver.nk - name: ProxyMode value: 'false' -- name: TelemetryOptOut - value: 'false' - name: deadline:targetTaskRunStatus value: READY - name: deadline:maxFailedTasksCount diff --git a/job_bundle_output_tests/noise-saver/expected_job_bundle/template.yaml b/job_bundle_output_tests/noise-saver/expected_job_bundle/template.yaml index cfd33ab..d37d7a4 100644 --- a/job_bundle_output_tests/noise-saver/expected_job_bundle/template.yaml +++ b/job_bundle_output_tests/noise-saver/expected_job_bundle/template.yaml @@ -59,12 +59,6 @@ parameterDefinitions: allowedValues: - 'true' - 'false' -- name: TelemetryOptOut - type: STRING - default: 'false' - allowedValues: - - 'true' - - 'false' steps: - name: Render parameterSpace: @@ -84,7 +78,6 @@ steps: continue_on_error: {{Param.ContinueOnError}} proxy: {{Param.ProxyMode}} script_file: '{{Param.NukeScriptFile}}' - telemetry_opt_out: {{Param.TelemetryOptOut}} write_nodes: - '{{Param.WriteNode}}' views: diff --git a/job_bundle_output_tests/ocio/expected_job_bundle/parameter_values.yaml b/job_bundle_output_tests/ocio/expected_job_bundle/parameter_values.yaml index a4de627..a2aa969 100644 --- a/job_bundle_output_tests/ocio/expected_job_bundle/parameter_values.yaml +++ b/job_bundle_output_tests/ocio/expected_job_bundle/parameter_values.yaml @@ -5,8 +5,6 @@ parameterValues: value: /normalized/job/bundle/dir/ocio.nk - name: ProxyMode value: 'false' -- name: TelemetryOptOut - value: 'false' - name: deadline:targetTaskRunStatus value: READY - name: deadline:maxFailedTasksCount diff --git a/job_bundle_output_tests/ocio/expected_job_bundle/template.yaml b/job_bundle_output_tests/ocio/expected_job_bundle/template.yaml index 68910b0..122697f 100644 --- a/job_bundle_output_tests/ocio/expected_job_bundle/template.yaml +++ b/job_bundle_output_tests/ocio/expected_job_bundle/template.yaml @@ -59,12 +59,6 @@ parameterDefinitions: allowedValues: - 'true' - 'false' -- name: TelemetryOptOut - type: STRING - default: 'false' - allowedValues: - - 'true' - - 'false' steps: - name: Render parameterSpace: @@ -84,7 +78,6 @@ steps: continue_on_error: {{Param.ContinueOnError}} proxy: {{Param.ProxyMode}} script_file: '{{Param.NukeScriptFile}}' - telemetry_opt_out: {{Param.TelemetryOptOut}} write_nodes: - '{{Param.WriteNode}}' views: diff --git a/pyproject.toml b/pyproject.toml index 2907cdf..272c345 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,10 +11,12 @@ requires-python = ">=3.7" dependencies = [ "deadline == 0.37.*", - "openjd-adaptor-runtime == 0.3.*", + "openjd-adaptor-runtime == 0.4.*", ] [project.scripts] +nuke-openjd = "deadline.nuke_adaptor.NukeAdaptor:main" +# The binary name 'NukeAdaptor' is deprecated. NukeAdaptor = "deadline.nuke_adaptor.NukeAdaptor:main" [tool.hatch.build] @@ -126,7 +128,7 @@ source = [ [tool.coverage.report] show_missing = true -fail_under = 73 +fail_under = 72 [tool.semantic_release] # Can be removed or set to true once we are v1 diff --git a/scripts/create_adaptor_packaging_artifact.sh b/scripts/create_adaptor_packaging_artifact.sh new file mode 100755 index 0000000..5659f61 --- /dev/null +++ b/scripts/create_adaptor_packaging_artifact.sh @@ -0,0 +1,181 @@ +#!/usr/bin/env bash +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +set -xeou pipefail + +APP=nuke +ADAPTOR_NAME=deadline-cloud-for-$APP + +# This script generates an tar.gz artifact from $ADAPTOR_NAME and its dependencies +# that can be used to create a package for running the adaptor. + +SCRIPTDIR=$(realpath $(dirname $0)) + +SOURCE=0 +# Python 3.11 is for https://vfxplatform.com/ CY2024 +PYTHON_VERSION=3.11 +CONDA_PLATFORM=linux-64 +TAR_BASE= + +while [ $# -gt 0 ]; do + case "${1}" in + --source) SOURCE=1 ; shift ;; + --platform) CONDA_PLATFORM="$2" ; shift 2 ;; + --python) PYTHON_VERSION="$2" ; shift 2 ;; + --tar-base) TAR_BASE="$2" ; shift 2 ;; + *) echo "Unexpected option: $1"; exit 1 ;; + esac +done + +if [ "$CONDA_PLATFORM" = "linux-64" ]; then + PYPI_PLATFORM=manylinux2014_x86_64 +elif [ "$CONDA_PLATFORM" = "win-64" ]; then + PYPI_PLATFORM=win_amd64 +elif [ "$CONDA_PLATFORM" = "osx-64" ]; then + PYPI_PLATFORM=macosx_10_9_x86_64 +else + echo "Unknown Conda operating system option --platform $CONDA_PLATFORM" + exit 1 +fi + +if [ "$TAR_BASE" = "" ]; then + TAR_BASE=$SCRIPTDIR/../$APP-openjd-py$PYTHON_VERSION-$CONDA_PLATFORM +fi + +# Create a temporary prefix +WORKDIR=$(mktemp -d adaptor-pkg.XXXXXXXXXX) +function cleanup_workdir { + echo "Cleaning up $WORKDIR" + rm -rf $WORKDIR +} +trap cleanup_workdir EXIT + +PREFIX=$WORKDIR/prefix + +if [ "$CONDA_PLATFORM" = "win-64" ]; then + BINDIR=$PREFIX/Library/bin + PACKAGEDIR=$PREFIX/Library/opt/$ADAPTOR_NAME +else + BINDIR=$PREFIX/bin + PACKAGEDIR=$PREFIX/opt/$ADAPTOR_NAME +fi + + +mkdir -p $PREFIX +mkdir -p $PACKAGEDIR +mkdir -p $BINDIR + +# Install the adaptor into the virtual env +if [ $SOURCE = 1 ]; then + # In source mode, openjd-adaptor-runtime-for-python must be alongside this adaptor source + RUNTIME_INSTALLABLE=$SCRIPTDIR/../../openjd-adaptor-runtime-for-python + ADAPTOR_INSTALLABLE=$SCRIPTDIR/.. + + if [ "$CONDA_PLATFORM" = "win-64" ]; then + DEPS="pyyaml jsonschema pywin32" + else + DEPS="pyyaml jsonschema" + fi + + pip install \ + --target $PACKAGEDIR \ + --platform $PYPI_PLATFORM \ + --python-version $PYTHON_VERSION \ + --ignore-installed \ + --only-binary=:all: \ + $DEPS + pip install \ + --target $PACKAGEDIR \ + --platform $PYPI_PLATFORM \ + --python-version $PYTHON_VERSION \ + --ignore-installed \ + --no-deps \ + $RUNTIME_INSTALLABLE \ + $ADAPTOR_INSTALLABLE +else + # In PyPI mode, PyPI and/or a CodeArtifact must have these packages + RUNTIME_INSTALLABLE=openjd-adaptor-runtime-for-python + ADAPTOR_INSTALLABLE=$ADAPTOR_NAME + + pip install \ + --target $PACKAGEDIR \ + --platform $PYPI_PLATFORM \ + --python-version $PYTHON_VERSION \ + --ignore-installed \ + --only-binary=:all: \ + $RUNTIME_INSTALLABLE + pip install \ + --target $PACKAGEDIR \ + --platform $PYPI_PLATFORM \ + --python-version $PYTHON_VERSION \ + --ignore-installed \ + --no-deps \ + $ADAPTOR_INSTALLABLE +fi + + +# Remove the submitter code +rm -r $PACKAGEDIR/deadline/*_submitter + +# Remove the bin dir if there is one +if [ -d $PACKAGEDIR/bin ]; then + rm -r $PACKAGEDIR/bin +fi + +PYSCRIPT="from pathlib import Path +import sys +reentry_exe = Path(sys.argv[0]).absolute() +sys.path.append(str(reentry_exe.parent.parent / \"opt\" / \"$ADAPTOR_NAME\")) +from deadline.${APP}_adaptor.${APP^}Adaptor.__main__ import main +sys.exit(main(reentry_exe=reentry_exe)) +" + +cat < $BINDIR/$APP-openjd +#!/usr/bin/env python3.11 +$PYSCRIPT +EOF + +# Temporary +cp $BINDIR/$APP-openjd $BINDIR/${APP^}Adaptor + +chmod u+x $BINDIR/$APP-openjd $BINDIR/${APP^}Adaptor + +if [ $CONDA_PLATFORM = "win-64" ]; then + # Install setuptools to get cli-64.exe + mkdir -p $WORKDIR/tmp + pip install \ + --target $WORKDIR/tmp \ + --platform $PYPI_PLATFORM \ + --python-version $PYTHON_VERSION \ + --ignore-installed \ + --no-deps \ + setuptools + + # Use setuptools' cli-64.exe to define the entry point + cat < $BINDIR/$APP-openjd-script.py +#!C:\\Path\\To\\Python.exe +$PYSCRIPT +EOF + cp $WORKDIR/tmp/setuptools/cli-64.exe $BINDIR/$APP-openjd.exe +fi + +# Everything between the first "-" and the next "+" is the package version number +PACKAGEVER=$(cd $PACKAGEDIR; echo deadline_cloud_for*) +PACKAGEVER=${PACKAGEVER#*-} +PACKAGEVER=${PACKAGEVER%+*} +echo "Package version number is $PACKAGEVER" + +# Create the tar artifact +GIT_TIMESTAMP="$(env TZ=UTC git log -1 --date=iso-strict-local --format="%ad")" +pushd $PREFIX +# See https://reproducible-builds.org/docs/archives/ for information about +# these options +#tar --mtime=$GIT_TIMESTAMP \ +# --sort=name \ +# --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime \ +# --owner=0 --group=0 --numeric-owner \ +# -cf $TAR_BASE . +# TODO Switch to the above command once the build environment has tar version > 1.28 +tar --owner=0 --group=0 --numeric-owner \ + -cf $TAR_BASE-$PACKAGEVER.tar.gz . +sha256sum $TAR_BASE-$PACKAGEVER.tar.gz +popd diff --git a/src/deadline/nuke_adaptor/NukeAdaptor/__main__.py b/src/deadline/nuke_adaptor/NukeAdaptor/__main__.py index d5ebffd..aee22fc 100644 --- a/src/deadline/nuke_adaptor/NukeAdaptor/__main__.py +++ b/src/deadline/nuke_adaptor/NukeAdaptor/__main__.py @@ -1,34 +1,37 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -import logging as _logging -import sys as _sys +import logging +import sys +import typing +import pathlib -from openjd.adaptor_runtime import EntryPoint as _EntryPoint +from openjd.adaptor_runtime import EntryPoint from .adaptor import NukeAdaptor __all__ = ["main"] -_logger = _logging.getLogger(__name__) +_logger = logging.getLogger(__name__) -def main() -> None: +def main(reentry_exe: typing.Optional[pathlib.Path] = None) -> int: """ Entry point for the Nuke Adaptor """ _logger.info("About to start the NukeAdaptor") - package_name = vars(_sys.modules[__name__])["__package__"] + package_name = vars(sys.modules[__name__])["__package__"] if not package_name: raise RuntimeError(f"Must be run as a module. Do not run {__file__} directly") try: - _EntryPoint(NukeAdaptor).start() + EntryPoint(NukeAdaptor).start(reentry_exe=reentry_exe) except Exception as e: _logger.error(f"Entrypoint failed: {e}") - _sys.exit(1) + return 1 _logger.info("Done NukeAdaptor main") + return 0 if __name__ == "__main__": - main() + sys.exit(main()) diff --git a/src/deadline/nuke_adaptor/NukeAdaptor/adaptor.py b/src/deadline/nuke_adaptor/NukeAdaptor/adaptor.py index c21acea..8f834c9 100644 --- a/src/deadline/nuke_adaptor/NukeAdaptor/adaptor.py +++ b/src/deadline/nuke_adaptor/NukeAdaptor/adaptor.py @@ -9,9 +9,19 @@ import threading import time import jsonschema # type: ignore -from typing import Callable, cast +from typing import Callable, cast, Any + +try: + get_deadline_cloud_library_telemetry_client: Any + from deadline.client.api import get_deadline_cloud_library_telemetry_client, TelemetryClient +except ModuleNotFoundError: + get_deadline_cloud_library_telemetry_client = None + + class TelemetryClient: # type: ignore[no-redef] + def record_event(self, *args, **kwargs): + pass + -from deadline.client.api import get_deadline_cloud_library_telemetry_client, TelemetryClient from openjd.adaptor_runtime.adaptors import Adaptor, AdaptorDataValidators from openjd.adaptor_runtime_client import Action from openjd.adaptor_runtime.process import LoggingSubprocess @@ -214,7 +224,7 @@ def _handle_error(self, match: re.Match) -> None: self._exc_info = RuntimeError(f"Nuke Encountered an Error: {match.group(0)}") @property - def server_socket_path(self) -> str: + def server_server_path(self) -> str: """ Performs a busy wait for the socket path that the adaptor server is running on, then returns it. @@ -226,11 +236,11 @@ def server_socket_path(self) -> str: str: The socket path the adaptor server is running on. """ is_timed_out = self._get_timer(self._SERVER_START_TIMEOUT_SECONDS) - while (self._server is None or self._server.socket_path is None) and not is_timed_out(): + while (self._server is None or self._server.server_path is None) and not is_timed_out(): time.sleep(0.01) - if self._server is not None and self._server.socket_path is not None: - return self._server.socket_path + if self._server is not None and self._server.server_path is not None: + return self._server.server_path raise RuntimeError("Could not find a socket because the server did not finish initializing") @@ -301,6 +311,8 @@ def on_start(self) -> None: self._populate_action_queue() # initialize telemetry client to handle opt out + # TODO: We will move this to a configuration file on the host, that can be controlled + # by a Queue Environment. self._get_deadline_telemetry_client(self.init_data.get("telemetry_opt_out", False)) self._record_adaptor_runtime_event( self.__class__.__name__, @@ -412,7 +424,7 @@ def on_cancel(self): def _start_nuke_server_thread(self) -> threading.Thread: """ Starts the nuke adaptor server in a thread. - Sets the environment variable "NUKE_ADAPTOR_SOCKET_PATH" to the socket the server is running + Sets the environment variable "NUKE_ADAPTOR_SERVER_PATH" to the socket the server is running on after the server has finished starting. Returns: @@ -429,7 +441,7 @@ def start_nuke_server() -> None: server_thread = threading.Thread(target=start_nuke_server) server_thread.start() - os.environ["NUKE_ADAPTOR_SOCKET_PATH"] = self.server_socket_path + os.environ["NUKE_ADAPTOR_SERVER_PATH"] = self.server_server_path return server_thread @@ -491,9 +503,12 @@ def _get_deadline_telemetry_client(self, adaptor_opt_out: bool = False) -> Telem """ Wrapper around the Deadline Client Library telemetry client, in order to set package-specific information """ - client = get_deadline_cloud_library_telemetry_client() - client.telemetry_opted_out = client.telemetry_opted_out or adaptor_opt_out - return client + if get_deadline_cloud_library_telemetry_client is not None: + client = get_deadline_cloud_library_telemetry_client() + client.telemetry_opted_out = client.telemetry_opted_out or adaptor_opt_out + return client + else: + return TelemetryClient() # type: ignore[call-arg] def _record_adaptor_runtime_event( self, adaptor_name: str, event_function_name: str, version: str diff --git a/src/deadline/nuke_adaptor/NukeClient/nuke_client.py b/src/deadline/nuke_adaptor/NukeClient/nuke_client.py index 0969528..765befa 100644 --- a/src/deadline/nuke_adaptor/NukeClient/nuke_client.py +++ b/src/deadline/nuke_adaptor/NukeClient/nuke_client.py @@ -42,8 +42,8 @@ class NukeClient(_HTTPClientInterface): Client for that runs in Nuke for the Nuke Adaptor """ - def __init__(self, socket_path: str) -> None: - super().__init__(socket_path=socket_path) + def __init__(self, server_path: str) -> None: + super().__init__(server_path=server_path) self.actions.update(NukeHandler().action_dict) def ensure_output_dir(): @@ -143,21 +143,21 @@ def _map_ocio_config(self): def main(): - socket_path = os.environ.get("NUKE_ADAPTOR_SOCKET_PATH") - if not socket_path: + server_path = os.environ.get("NUKE_ADAPTOR_SERVER_PATH") + if not server_path: raise OSError( "NukeClient cannot connect to the Adaptor because the environment variable " - "NUKE_ADAPTOR_SOCKET_PATH does not exist" + "NUKE_ADAPTOR_SERVER_PATH does not exist" ) - if not os.path.exists(socket_path): + if not os.path.exists(server_path): raise OSError( "NukeClient cannot connect to the Adaptor because the socket at the path defined by " - "the environment variable NUKE_ADAPTOR_SOCKET_PATH does not exist. Got: " - f"{os.environ['NUKE_ADAPTOR_SOCKET_PATH']}" + "the environment variable NUKE_ADAPTOR_SERVER_PATH does not exist. Got: " + f"{os.environ['NUKE_ADAPTOR_SERVER_PATH']}" ) - client = NukeClient(socket_path) + client = NukeClient(server_path) client.poll() diff --git a/src/deadline/nuke_submitter/deadline_submitter_for_nuke.py b/src/deadline/nuke_submitter/deadline_submitter_for_nuke.py index dc88ffe..c8e8d1a 100644 --- a/src/deadline/nuke_submitter/deadline_submitter_for_nuke.py +++ b/src/deadline/nuke_submitter/deadline_submitter_for_nuke.py @@ -24,6 +24,7 @@ QMessageBox, ) +from ._version import version_tuple as adaptor_version_tuple from .assets import get_nuke_script_file, get_scene_asset_references, find_all_write_nodes from .data_classes import RenderSubmitterUISettings from .ui.components.scene_settings_tab import SceneSettingsWidget @@ -176,11 +177,6 @@ def _get_parameter_values( # Set the Nuke script file value parameter_values.append({"name": "NukeScriptFile", "value": get_nuke_script_file()}) - # Set the TelemetryOptOut parameter value - parameter_values.append( - {"name": "TelemetryOptOut", "value": "true" if settings.is_telemetry_opted_out else "false"} - ) - # Set the WriteNode parameter value if write_node_name: parameter_values.append({"name": "WriteNode", "value": write_node_name}) @@ -206,21 +202,27 @@ def _get_parameter_values( + f"{', '.join(parameter_overlap)}" ) - # If we're overriding the adaptor with wheels, remove deadline_cloud_for_nuke from the RezPackages + # If we're overriding the adaptor with wheels, remove the adaptor from the Packages parameters if settings.include_adaptor_wheels: rez_param = {} - # Find the RezPackages parameter definition + conda_param = {} + # Find the Packages parameter definition for param in queue_parameters: if param["name"] == "RezPackages": rez_param = param - break - # Remove the deadline_cloud_for_nuke rez package + if param["name"] == "CondaPackages": + conda_param = param + # Remove the deadline_cloud_for_nuke/nuke-openjd package if rez_param: rez_param["value"] = " ".join( pkg for pkg in rez_param["value"].split() if not pkg.startswith("deadline_cloud_for_nuke") ) + if conda_param: + conda_param["value"] = " ".join( + pkg for pkg in conda_param["value"].split() if not pkg.startswith("nuke-openjd") + ) parameter_values.extend( {"name": param["name"], "value": param["value"]} for param in queue_parameters @@ -324,11 +326,18 @@ def on_create_job_bundle_callback( if not g_submitter_dialog: nuke_version = nuke.env["NukeVersionMajor"] + adaptor_version = ".".join(str(v) for v in adaptor_version_tuple[:2]) + + # Need Nuke and the Nuke OpenJD application interface adaptor + rez_packages = f"nuke-{nuke_version} deadline_cloud_for_nuke" + conda_packages = f"nuke={nuke_version}.* nuke-openjd={adaptor_version}.*" + g_submitter_dialog = SubmitJobToDeadlineDialog( job_setup_widget_type=SceneSettingsWidget, initial_job_settings=render_settings, initial_shared_parameter_values={ - "RezPackages": f"nuke-{nuke_version} deadline_cloud_for_nuke" + "RezPackages": rez_packages, + "CondaPackages": conda_packages, }, auto_detected_attachments=auto_detected_attachments, attachments=attachments, diff --git a/src/deadline/nuke_submitter/default_nuke_job_template.yaml b/src/deadline/nuke_submitter/default_nuke_job_template.yaml index 8bfecbb..942de29 100644 --- a/src/deadline/nuke_submitter/default_nuke_job_template.yaml +++ b/src/deadline/nuke_submitter/default_nuke_job_template.yaml @@ -57,12 +57,6 @@ parameterDefinitions: allowedValues: - 'true' - 'false' -- name: TelemetryOptOut - type: STRING - default: 'false' - allowedValues: - - 'true' - - 'false' steps: - name: Render parameterSpace: @@ -82,7 +76,6 @@ steps: continue_on_error: {{Param.ContinueOnError}} proxy: {{Param.ProxyMode}} script_file: '{{Param.NukeScriptFile}}' - telemetry_opt_out: {{Param.TelemetryOptOut}} write_nodes: - '{{Param.WriteNode}}' views: diff --git a/src/deadline/nuke_submitter/job_bundle_output_test_runner.py b/src/deadline/nuke_submitter/job_bundle_output_test_runner.py index 4da0067..7a59c60 100644 --- a/src/deadline/nuke_submitter/job_bundle_output_test_runner.py +++ b/src/deadline/nuke_submitter/job_bundle_output_test_runner.py @@ -231,7 +231,16 @@ def _run_job_bundle_output_test(test_dir: str, dcc_scene_file: str, report_fh, m contents = contents.replace(tempdir, "/normalized/job/bundle/dir") contents = contents.replace(tempdir.replace("\\", "/"), "/normalized/job/bundle/dir") + # Windows corner case + contents = contents.replace("C:\\tmp\\", "/tmp/") + contents = contents.replace("C:\\tmp", "/tmp") + contents = contents.replace("C:/tmp", "/tmp") + if os.getcwd() != "/": + contents = contents.replace(os.getcwd() + "\\", "/normalized/cwd/") + contents = contents.replace( + os.getcwd().replace("\\", "/") + "\\", "/normalized/cwd/" + ) contents = contents.replace(os.getcwd(), "/normalized/cwd") else: # Mac specific cases diff --git a/test/unit/deadline_adaptor_for_nuke/NukeAdaptor/test_adaptor.py b/test/unit/deadline_adaptor_for_nuke/NukeAdaptor/test_adaptor.py index ff481e3..4f7fb85 100644 --- a/test/unit/deadline_adaptor_for_nuke/NukeAdaptor/test_adaptor.py +++ b/test/unit/deadline_adaptor_for_nuke/NukeAdaptor/test_adaptor.py @@ -31,7 +31,6 @@ def init_data() -> dict: "write_nodes": ["Write1", "Write2", "Write3"], "views": ["left", "right"], "script_file": "/path/to/some/nukescript.nk", - "telemetry_opt_out": True, } @@ -59,7 +58,7 @@ def test_no_error( ) -> None: """Tests that on_start completes without error""" adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" adaptor.on_start() @patch("time.sleep") @@ -80,7 +79,7 @@ def test_waits_for_server_socket( socket_mock = PropertyMock( side_effect=[None, None, None, "/tmp/9999", "/tmp/9999", "/tmp/9999"] ) - type(mock_server.return_value).socket_path = socket_mock + type(mock_server.return_value).server_path = socket_mock # WHEN adaptor.on_start() @@ -149,7 +148,7 @@ def test_nuke_init_timeout( """ # GIVEN adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" new_timeout = 0.01 with patch.object(adaptor, "_NUKE_START_TIMEOUT_SECONDS", new_timeout), pytest.raises( @@ -181,7 +180,7 @@ def test_nuke_init_fail( """ # GIVEN adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" with pytest.raises(RuntimeError) as exc_info: # WHEN @@ -205,7 +204,7 @@ def test_populate_action_queue( # GIVEN mock_actions_queue.__len__.return_value = 0 adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" # WHEN adaptor.on_start() @@ -241,7 +240,7 @@ def test_populate_action_queue_less_init_data( } mock_actions_queue.__len__.return_value = 0 adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" expected_action_names_queued = init_data.keys() & _NUKE_INIT_KEYS | set(_FIRST_NUKE_ACTIONS) # WHEN @@ -290,7 +289,7 @@ def test_on_run( """Tests that on_run waits for completion""" # GIVEN adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" # First side_effect value consumed by setter is_rendering_mock = PropertyMock(side_effect=[None, True, False]) NukeAdaptor._is_rendering = is_rendering_mock @@ -333,7 +332,7 @@ def test_on_run_render_fail( mock_nuke_is_running.side_effect = [True, True, True, False, False] mock_logging_subprocess.return_value.returncode = 1 adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" adaptor.on_start() # WHEN @@ -366,7 +365,7 @@ def test_run_data_wrong_schema( """Tests that on_run waits for completion""" # GIVEN adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" # First side_effect value consumed by setter mock_nuke_is_running.side_effect = [True] run_data = {"bad": "schema"} @@ -396,7 +395,7 @@ def test_on_stop( ) -> None: # GIVEN adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" is_rendering_mock = PropertyMock(return_value=False) NukeAdaptor._is_rendering = is_rendering_mock adaptor.on_start() @@ -498,7 +497,7 @@ def test_on_cleanup( ) -> None: # GIVEN adaptor = NukeAdaptor(init_data) - mock_server.return_value.socket_path = "/tmp/9999" + mock_server.return_value.server_path = "/tmp/9999" is_rendering_mock = PropertyMock(return_value=False) NukeAdaptor._is_rendering = is_rendering_mock diff --git a/test/unit/deadline_adaptor_for_nuke/NukeClient/test_client.py b/test/unit/deadline_adaptor_for_nuke/NukeClient/test_client.py index 0c04f0f..e3afc4c 100644 --- a/test/unit/deadline_adaptor_for_nuke/NukeClient/test_client.py +++ b/test/unit/deadline_adaptor_for_nuke/NukeClient/test_client.py @@ -30,14 +30,14 @@ def test_nukeclient(self, mock_handler) -> None: mock_handler.return_value.action_dict = handler_action_dict # WHEN - client = NukeClient(socket_path="/tmp/9999") + client = NukeClient(server_path="/tmp/9999") # THEN mock_handler.assert_called_once() assert handler_action_dict.items() <= client.actions.items() @patch("deadline.nuke_adaptor.NukeClient.nuke_client.os.path.exists") - @patch.dict(os.environ, {"NUKE_ADAPTOR_SOCKET_PATH": "9999"}) + @patch.dict(os.environ, {"NUKE_ADAPTOR_SERVER_PATH": "9999"}) @patch("deadline.nuke_adaptor.NukeClient.NukeClient.poll") @patch("deadline.nuke_adaptor.NukeClient.nuke_client._HTTPClientInterface") def test_main(self, mock_httpclient: Mock, mock_poll: Mock, mock_exists: Mock) -> None: @@ -63,12 +63,12 @@ def test_main_no_server_socket(self, mock_poll: Mock) -> None: # THEN assert str(exc_info.value) == ( "NukeClient cannot connect to the Adaptor because the environment variable " - "NUKE_ADAPTOR_SOCKET_PATH does not exist" + "NUKE_ADAPTOR_SERVER_PATH does not exist" ) mock_poll.assert_not_called() @patch("deadline.nuke_adaptor.NukeClient.nuke_client.os.path.exists") - @patch.dict(os.environ, {"NUKE_ADAPTOR_SOCKET_PATH": "/a/path/that/does/not/exist"}) + @patch.dict(os.environ, {"NUKE_ADAPTOR_SERVER_PATH": "/a/path/that/does/not/exist"}) @patch("deadline.nuke_adaptor.NukeClient.NukeClient.poll") def test_main_server_socket_not_exist(self, mock_poll: Mock, mock_exists: Mock) -> None: """Tests that the main method raises an OSError if the server socket does not exist""" @@ -83,8 +83,8 @@ def test_main_server_socket_not_exist(self, mock_poll: Mock, mock_exists: Mock) mock_exists.assert_called_once_with("/a/path/that/does/not/exist") assert str(exc_info.value) == ( "NukeClient cannot connect to the Adaptor because the socket at the path defined by " - "the environment variable NUKE_ADAPTOR_SOCKET_PATH does not exist. Got: " - f"{os.environ['NUKE_ADAPTOR_SOCKET_PATH']}" + "the environment variable NUKE_ADAPTOR_SERVER_PATH does not exist. Got: " + f"{os.environ['NUKE_ADAPTOR_SERVER_PATH']}" ) mock_poll.assert_not_called() @@ -95,7 +95,7 @@ def test_close(self, mock_script_close: Mock, mock_script_exit: Mock): Test that nuke closes and exits on client.close() """ # GIVEN - client = NukeClient(socket_path="/tmp/9999") + client = NukeClient(server_path="/tmp/9999") # WHEN client.close() @@ -111,7 +111,7 @@ def test_graceful_shutdown(self, mock_script_close: Mock, mock_script_exit: Mock Test that nuke closes and exits on client.graceful_shutdown """ # GIVEN - client = NukeClient(socket_path="/tmp/9999") + client = NukeClient(server_path="/tmp/9999") # WHEN client.graceful_shutdown(1, Mock()) @@ -127,7 +127,7 @@ def test_ensure_output_dir(self, mock_os: Mock, is_dir: bool): Test that the ensure_output_dir handle which is run before each render works properly """ # GIVEN - NukeClient(socket_path="/tmp/9999") + NukeClient(server_path="/tmp/9999") mock_os.path.isdir.return_value = is_dir ensure_output_dir = nuke.addBeforeRender.call_args[0][0] @@ -192,7 +192,7 @@ def test_map_path( ): # GIVEN mocked_path_class.side_effect = new_path_class - client = NukeClient(socket_path="/tmp/9999") + client = NukeClient(server_path="/tmp/9999") mock_map_path.return_value = client_mapped mock_path_mapping_rules.return_value = rules @@ -261,7 +261,7 @@ def test_recursive_map_path( ): # GIVEN mocked_path_class.side_effect = new_path_class - client = NukeClient(socket_path="/tmp/9999") + client = NukeClient(server_path="/tmp/9999") mock_map_path.return_value = client_mapped mock_path_mapping_rules.return_value = rules @@ -307,7 +307,7 @@ def map_path(path: str): ) temp_socket_file = tempfile.TemporaryFile() - client = NukeClient(socket_path=temp_socket_file.name) + client = NukeClient(server_path=temp_socket_file.name) # WHEN client._map_ocio_config()