diff --git a/app.py b/app.py
index 3d3b4ec..79eb06f 100644
--- a/app.py
+++ b/app.py
@@ -31,14 +31,19 @@ def init_app(self):
# Use the Launchers defined in the tk_multi_launchapp payload
# to do all of the heavy lifting for this app
app_payload = self.import_module("tk_multi_launchapp")
- if self.get_setting("use_software_entity"):
- # For zero config type setups
- self._launcher = app_payload.SoftwareEntityLauncher()
- else:
- # For traditional setups
- self._launcher = app_payload.SingleConfigLauncher()
-
- # Register the appropriate DCC launch commands
+ # if self.get_setting("use_software_entity"):
+ # # For zero config type setups
+ # self._launcher = app_payload.SoftwareEntityLauncher()
+ # else:
+ # # For traditional setups
+ # self._launcher = app_payload.SingleConfigLauncher()
+
+ self._launcher = self.execute_hook_method(
+ "hook_launcher", "init", base_class=app_payload.BaseLauncher
+ )
+
+ # # Register the appropriate DCC launch commands
+
self._launcher.register_launch_commands()
def launch_from_path_and_context(self, path, context, version=None):
diff --git a/python/tk_multi_launchapp/single_config_launcher.py b/hooks/single_config_launcher.py
similarity index 85%
rename from python/tk_multi_launchapp/single_config_launcher.py
rename to hooks/single_config_launcher.py
index 60dcf7f..eb368dc 100644
--- a/python/tk_multi_launchapp/single_config_launcher.py
+++ b/hooks/single_config_launcher.py
@@ -13,27 +13,30 @@
import sgtk
from sgtk import TankError
-from .base_launcher import BaseLauncher
+HookBaseClass = sgtk.get_hook_baseclass()
-class SingleConfigLauncher(BaseLauncher):
+class SingleConfigLauncher(HookBaseClass):
"""
Launches a DCC based on traditional configuration settings.
"""
- def __init__(self):
+ def init(self):
"""
Initialize base class and member values
"""
- BaseLauncher.__init__(self)
+
+ super(SingleConfigLauncher, self).init()
# Store required information to launch the app as members.
- self._app_path = self._tk_app.get_setting("%s_path" % self._platform_name, "")
- self._app_args = self._tk_app.get_setting("%s_args" % self._platform_name, "")
- self._app_menu_name = self._tk_app.get_setting("menu_name")
- self._app_engine = self._tk_app.get_setting("engine")
- self._app_group = self._tk_app.get_setting("group")
- self._is_group_default = self._tk_app.get_setting("group_default")
+ self._app_path = self.parent.get_setting("%s_path" % self._platform_name, "")
+ self._app_args = self.parent.get_setting("%s_args" % self._platform_name, "")
+ self._app_menu_name = self.parent.get_setting("menu_name")
+ self._app_engine = self.parent.get_setting("engine")
+ self._app_group = self.parent.get_setting("group")
+ self._is_group_default = self.parent.get_setting("group_default")
+
+ return self
def register_launch_commands(self):
"""
@@ -46,11 +49,11 @@ def register_launch_commands(self):
return
# get icon value, replacing tokens if needed
- app_icon = self._tk_app.get_setting("icon")
+ app_icon = self.parent.get_setting("icon")
if app_icon.startswith("{target_engine}"):
if self._app_engine:
engine_path = sgtk.platform.get_engine_path(
- self._app_engine, self._tk_app.sgtk, self._tk_app.context
+ self._app_engine, self.parent.sgtk, self.parent.context
)
if engine_path:
app_icon = app_icon.replace("{target_engine}", engine_path, 1)
@@ -65,7 +68,7 @@ def register_launch_commands(self):
app_icon = ""
if app_icon.startswith("{config_path}"):
- config_path = self._tk_app.sgtk.pipeline_configuration.get_config_location()
+ config_path = self.parent.sgtk.pipeline_configuration.get_config_location()
if not config_path:
raise TankError(
"No pipeline configuration path found for '{config_path}' replacement."
@@ -76,13 +79,13 @@ def register_launch_commands(self):
app_icon = app_icon.replace("/", os.path.sep)
# Initialize per version
- app_versions = self._tk_app.get_setting("versions") or []
+ app_versions = self.parent.get_setting("versions") or []
if app_versions:
# If a list of versions has been specified, the "group_default" configuration
# setting is invalid because it cannot be applied to each generated command.
# Set the group default to the highest version in the list instead.
sorted_versions = self._sort_versions(app_versions)
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Unable to apply group '%s' group_default value to list of DCC versions : %s. "
"Setting group '%s' default to highest version '%s' instead."
% (
@@ -131,7 +134,7 @@ def launch_from_path(self, path, version=None):
:param path: File path DCC should open after launch.
:param version: (Optional) Specific version of DCC to launch.
"""
- context = self._tk_app.sgtk.context_from_path(path)
+ context = self.parent.sgtk.context_from_path(path)
self._launch_app(
self._app_menu_name,
self._app_engine,
diff --git a/python/tk_multi_launchapp/software_entity_launcher.py b/hooks/software_entity_launcher.py
similarity index 90%
rename from python/tk_multi_launchapp/software_entity_launcher.py
rename to hooks/software_entity_launcher.py
index ce20d1e..f5de9a7 100644
--- a/python/tk_multi_launchapp/software_entity_launcher.py
+++ b/hooks/software_entity_launcher.py
@@ -13,10 +13,10 @@
import sgtk
-from .base_launcher import BaseLauncher
+HookBaseClass = sgtk.get_hook_baseclass()
-class SoftwareEntityLauncher(BaseLauncher):
+class SoftwareEntityLauncher(HookBaseClass):
"""
Launches a DCC application based on site Software entity entries.
@@ -68,8 +68,8 @@ def register_launch_commands(self):
for sw_entity in sw_entities:
- self._tk_app.log_debug("-" * 20)
- self._tk_app.log_debug(
+ self.parent.log_debug("-" * 20)
+ self.parent.log_debug(
"Parsing Software entity for launch commands:\n%s"
% pprint.pformat(sw_entity, indent=4)
)
@@ -107,12 +107,12 @@ def register_launch_commands(self):
):
# all paths are none - we are in automatic mode
- self._tk_app.log_debug("All path fields are None. Automatic mode.")
+ self.parent.log_debug("All path fields are None. Automatic mode.")
# make sure we have an engine defined when running in automatic mode
# the engine implements the software discovery logic and is therefore required
if engine_str is None:
- self._tk_app.log_debug(
+ self.parent.log_debug(
"No engine set. Skipping this software entity."
)
continue
@@ -135,13 +135,13 @@ def register_launch_commands(self):
else:
# one or more path fields are not none. This means manual mode.
- self._tk_app.log_debug(
+ self.parent.log_debug(
"One or more path fields are not None. Manual mode."
)
if sw_entity[app_path_field] is None:
# manual mode but nothing to do for our os
- self._tk_app.log_debug(
+ self.parent.log_debug(
"No path defined for current platform (field %s) - skipping."
% app_path_field
)
@@ -178,7 +178,7 @@ def launch_from_path(self, path, version=None):
:param version: (Optional) Specific version of DCC to launch.
"""
# This functionality is not supported for Software entities.
- self._tk_app.log_error(
+ self.parent.log_error(
"launch_from_path() is not supported by SoftwareEntityLauncher. "
"Please register individual application launch commands in your "
"Project's configuration to use this functionality."
@@ -194,7 +194,7 @@ def launch_from_path_and_context(self, path, context, version=None):
:param version: (Optional) Specific version of DCC to launch.
"""
# This functionality is not supported for Software entities.
- self._tk_app.log_error(
+ self.parent.log_error(
"launch_from_path_and_context() is not supported by "
"SoftwareEntityLauncher. Please register individual application "
"launch commands in your Project's configuration to use this "
@@ -214,12 +214,12 @@ def _get_sg_software_entities(self):
# check that software entity is supported
if self.__get_sg_server_version() < (7, 2, 0):
- self._tk_app.log_warning(
+ self.parent.log_warning(
"Your version of SG does not support Software entity based launching."
)
return []
- scan_all_projects = self._tk_app.get_setting("scan_all_projects") or False
+ scan_all_projects = self.parent.get_setting("scan_all_projects") or False
# Determine the information to retrieve from Shotgun
# Use filters to retrieve Software entities that match specified
@@ -237,7 +237,7 @@ def _get_sg_software_entities(self):
# Next handle Project restrictions. Always include Software entities
# that have no Project restrictions.
project_filters = [["projects", "is", None]]
- current_project = self._tk_app.context.project
+ current_project = self.parent.context.project
if current_project:
# If a Project is defined in the current context, retrieve
# Software entities that have either no Project restrictions OR
@@ -253,7 +253,7 @@ def _get_sg_software_entities(self):
# Now Group and User restrictions. Always retrieve Software entities
# that have no Group or User restrictions.
- current_user = self._tk_app.context.user
+ current_user = self.parent.context.user
# No user restriction filter.
user_group_filter = ["user_restrictions", "is", None]
@@ -302,19 +302,19 @@ def _get_sg_software_entities(self):
]
# Add any user defined fields to the list of fields we should request.
- sw_fields += self._tk_app.get_setting("software_entity_extra_fields")
+ sw_fields += self.parent.get_setting("software_entity_extra_fields")
# Log the resolved filter.
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Searching for Software entities matching filters:\n%s"
% (pprint.pformat(sw_filters, indent=4),)
)
- sw_entities = self._tk_app.shotgun.find("Software", sw_filters, sw_fields)
+ sw_entities = self.parent.shotgun.find("Software", sw_filters, sw_fields)
if not sw_entities:
# No Entities found matching filters, nothing to do.
- self._tk_app.log_debug("No matching SG Software entities found.")
+ self.parent.log_debug("No matching SG Software entities found.")
else:
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Got software data from ShotGrid:\n%s" % pprint.pformat(sw_entities)
)
@@ -356,14 +356,14 @@ def _scan_for_software_and_register(
"""
# No application path was specified, triggering "auto discovery" mode. Attempt to
# find relevant application path(s) from the engine launcher.
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Attempting to auto discover software for %s." % engine_str
)
software_versions = self._scan_for_software(
engine_str, dcc_versions, dcc_products
)
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Scan detected %d software versions" % len(software_versions)
)
@@ -375,15 +375,15 @@ def _scan_for_software_and_register(
if len(sorted_versions) > 1 and is_group_default:
# there is more than one match and we have requested that this is the
# group default. In this case make the highest version the group default.
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Multiple matches for the group default. Will use the highest version "
"number as the default."
)
for software_version in software_versions:
# run before launch hook
- self._tk_app.log_debug("Running before register command hook...")
- launch_engine_str = self._tk_app.execute_hook_method(
+ self.parent.log_debug("Running before register command hook...")
+ launch_engine_str = self.parent.execute_hook_method(
"hook_before_register_command",
"determine_engine_instance_name",
software_version=software_version,
@@ -400,7 +400,7 @@ def _scan_for_software_and_register(
# is determined by the hook. We need to check for the same possible
# issue here since the requested engine instance has changed.
if launch_engine_str != engine_str:
- self._tk_app.logger.debug(
+ self.parent.logger.debug(
"The before_register_command hook changed the engine instance "
"to be %s.",
launch_engine_str,
@@ -410,10 +410,10 @@ def _scan_for_software_and_register(
# We don't need the returned env and descriptor. We only
# care whether it raises or not.
sgtk.platform.engine.get_env_and_descriptor_for_engine(
- launch_engine_str, self._tk_app.sgtk, self._tk_app.context
+ launch_engine_str, self.parent.sgtk, self.parent.context
)
except sgtk.platform.TankMissingEngineError:
- self._tk_app.logger.debug(
+ self.parent.logger.debug(
"The engine instance requested by before_register_command (%s) "
"does not exist in the current environment. The launcher will "
"not be registered as a result.",
@@ -423,8 +423,8 @@ def _scan_for_software_and_register(
# We need to check to see if the engine instance associated with
# the launch command is something we've been configured to skip.
- if launch_engine_str in self._tk_app.get_setting("skip_engine_instances"):
- self._tk_app.logger.debug(
+ if launch_engine_str in self.parent.get_setting("skip_engine_instances"):
+ self.parent.logger.debug(
"The %s engine instance has been configured to be skipped by way "
"of the skip_engine_instances app setting. The launcher command "
"for %r will not be registered.",
@@ -506,7 +506,7 @@ def _manual_register(
if len(sorted_versions) > 1 and is_group_default:
# there is more than one match and we have requested that this is the
# group default. In this case make the highest version the group default.
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Multiple matches for the group default. Will use the highest version "
"number as the default."
)
@@ -558,24 +558,24 @@ def _extract_thumbnail(self, entity_type, entity_id, sg_thumb_url):
:param sg_thumb_url: The thumbnail url for the given record
:returns: path to local image
"""
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Attempting to extract high res thumbnail from %s %s"
% (entity_type, entity_id)
)
default_thumbnail_location = os.path.join(
- self._tk_app.disk_location, "icon_256.png"
+ self.parent.disk_location, "icon_256.png"
)
if sg_thumb_url is None:
- self._tk_app.log_debug(
+ self.parent.log_debug(
"No thumbnail is set in ShotGrid. Falling back on default."
)
# use the launch app icon
return default_thumbnail_location
- if not self._tk_app.engine.has_ui:
- self._tk_app.log_debug(
+ if not self.parent.engine.has_ui:
+ self.parent.log_debug(
"Runtime environment does not have Qt. Skipping extraction."
)
# use the launch app icon
@@ -584,26 +584,25 @@ def _extract_thumbnail(self, entity_type, entity_id, sg_thumb_url):
# all good to go - download the target icon
# Import sgutils after ui has been confirmed because it has dependencies on Qt.
- shotgun_data = sgtk.platform.import_framework(
- "tk-framework-shotgunutils", "shotgun_data"
- )
+ fw = self.load_framework("tk-framework-shotgunutils_v5.x.x")
+ shotgun_data = fw.import_module("shotgun_data")
# Download the Software thumbnail source from Shotgun and cache for reuse.
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Downloading app icon from %s %s ..." % (entity_type, entity_id)
)
try:
icon_path = shotgun_data.ShotgunDataRetriever.download_thumbnail_source(
- entity_type, entity_id, self._tk_app
+ entity_type, entity_id, self.parent
)
except Exception:
- self._tk_app.logger.exception(
+ self.parent.logger.exception(
"There was a problem downloading the thumbnail:"
)
return default_thumbnail_location
else:
- self._tk_app.log_debug("...download complete: %s" % icon_path)
+ self.parent.log_debug("...download complete: %s" % icon_path)
return icon_path
@@ -629,18 +628,18 @@ def _scan_for_software(self, engine, versions, products):
"""
# First try to construct the engine launcher for the specified engine.
try:
- self._tk_app.log_debug("Initializing engine launcher for %s." % engine)
+ self.parent.log_debug("Initializing engine launcher for %s." % engine)
engine_launcher = sgtk.platform.create_engine_launcher(
- self._tk_app.sgtk, self._tk_app.context, engine, versions, products
+ self.parent.sgtk, self.parent.context, engine, versions, products
)
if not engine_launcher:
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Toolkit engine %s does not support scanning for local DCC "
"applications." % engine
)
return []
except Exception as e:
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Unable to construct engine launcher for %s. Cannot determine "
"corresponding DCC application information:\n%s" % (engine, e)
)
@@ -648,12 +647,12 @@ def _scan_for_software(self, engine, versions, products):
# Next try to scan for available applications for this engine.
try:
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Scanning for Toolkit engine %s local applications." % engine
)
software_versions = engine_launcher.scan_software()
except Exception as e:
- self._tk_app.log_warning(
+ self.parent.log_warning(
"Caught unexpected error scanning for DCC applications corresponding "
"to Toolkit engine %s:\n%s\n%s" % (engine, e, traceback.format_exc())
)
@@ -668,7 +667,7 @@ def __get_sg_server_version(self):
:returns: Tuple of (major, minor, patch) versions.
"""
- sg_major_ver = self._tk_app.shotgun.server_info["version"][0]
- sg_minor_ver = self._tk_app.shotgun.server_info["version"][1]
- sg_patch_ver = self._tk_app.shotgun.server_info["version"][2]
+ sg_major_ver = self.parent.shotgun.server_info["version"][0]
+ sg_minor_ver = self.parent.shotgun.server_info["version"][1]
+ sg_patch_ver = self.parent.shotgun.server_info["version"][2]
return sg_major_ver, sg_minor_ver, sg_patch_ver
diff --git a/info.yml b/info.yml
index 71589e6..c038f40 100644
--- a/info.yml
+++ b/info.yml
@@ -10,33 +10,26 @@
# Metadata defining the behaviour and requirements for this app
-
# expected fields in the configuration file for this app
configuration:
-
- use_software_entity:
- type: bool
- description: Whether to use ShotGrid Software Entities to register
- launch commands for available DCCs.
- default_value: false
-
software_entity_extra_fields:
type: list
allows_empty: True
values:
type: str
default_value: []
- description: "A list of Software entity field code names that should be fetched and
- and passed to the hooks as part of the Software entity dictionary.
- The main fields are already fetched and provided by default, but this
- allows custom fields to be specified without needing to perform a second
- look up in ShotGrid."
+ description:
+ "A list of Software entity field code names that should be fetched and
+ and passed to the hooks as part of the Software entity dictionary.
+ The main fields are already fetched and provided by default, but this
+ allows custom fields to be specified without needing to perform a second
+ look up in ShotGrid."
scan_all_projects:
type: bool
description: When true, and when use_software_entity is true, launchers
- will be registered for all projects instead of only the
- current environment's project.
+ will be registered for all projects instead of only the
+ current environment's project.
default_value: false
menu_name:
@@ -45,15 +38,16 @@ configuration:
default_value: ""
icon:
- type: str
- description: "The path to the icon to appear for the application. If the
- value starts with '{target_engine}' then the remainder of the
- path will be relative to the root of the engine's install. If
- the value starts with '{config_path}' then the remainder of the
- path will be relative to the root of the configuration. The
- path should use forward slashes which will be replaced with
- the correct operating system separator when used."
- default_value: "{target_engine}/icon_256.png"
+ type: str
+ description:
+ "The path to the icon to appear for the application. If the
+ value starts with '{target_engine}' then the remainder of the
+ path will be relative to the root of the engine's install. If
+ the value starts with '{config_path}' then the remainder of the
+ path will be relative to the root of the configuration. The
+ path should use forward slashes which will be replaced with
+ the correct operating system separator when used."
+ default_value: "{target_engine}/icon_256.png"
# Path information for multiple platforms
windows_path:
@@ -88,10 +82,11 @@ configuration:
engine:
type: str
- description: "The name of the ShotGrid engine to start. This is typically the application
- name prefixed with tk, e.g. tk-maya, tk-nuke, tk-photoshop etc. If you set
- this to an empty string, no toolkit engine will be started, meaning that
- you can launch applications that do not have toolkit engines set up."
+ description:
+ "The name of the ShotGrid engine to start. This is typically the application
+ name prefixed with tk, e.g. tk-maya, tk-nuke, tk-photoshop etc. If you set
+ this to an empty string, no toolkit engine will be started, meaning that
+ you can launch applications that do not have toolkit engines set up."
default_value: ""
group:
@@ -101,33 +96,35 @@ configuration:
group_default:
type: bool
- description: "Boolean value indicating whether this command should represent the group as
- a whole. Setting this value to True indicates that this is the command to run and
- display in applications that show a single button for each named group."
+ description:
+ "Boolean value indicating whether this command should represent the group as
+ a whole. Setting this value to True indicates that this is the command to run and
+ display in applications that show a single button for each named group."
default_value: False
defer_keyword:
type: str
default_value: ""
- description: "Advanced parameter. This allows for advanced customization around deferred folder creation.
- Deferred folder creation allows for the creation of partial subfolder structures depending
- on a specific keyword (see main documentation for details). Before an app is launched, folders
- are automatically created and by default (e.g. if you leave this setting as null),
- the launch app will pass the name of the engine as the deferred folder creation keyword.
- This makes it easy to set up deferred rules in your folder creation config for tk-maya,
- tk-nuke etc. However, if you for example wanted to set up specific deferred folder structures
- for Nuke and Nuke X (both running the nuke engine), you need a finer granularity. This setting
- can then be used to override the default behaviour of just passing the engine name. Instead, you
- can pass any string into the deferred folder creation (for example 'nuke' and 'nuke_x' in the case
- above). This parameter is also useful if you want to use deferred folder creation in
- conjunction with launching of apps which do not have a toolkit engine defined - for these
- app launch instances, the engine setting is left blank, and therefore no engine name is passed
- into the deferred folder creation. In such cases you can utilize this parameter to control
- the deferred folder creation.
-
- You can specify multiple keywords using a comma as a delimiter (eg. 'nuke, nuke_x').
- This will trigger folder creation for folders in your schema that have any
- of these values in their deferred folder creation setting."
+ description:
+ "Advanced parameter. This allows for advanced customization around deferred folder creation.
+ Deferred folder creation allows for the creation of partial subfolder structures depending
+ on a specific keyword (see main documentation for details). Before an app is launched, folders
+ are automatically created and by default (e.g. if you leave this setting as null),
+ the launch app will pass the name of the engine as the deferred folder creation keyword.
+ This makes it easy to set up deferred rules in your folder creation config for tk-maya,
+ tk-nuke etc. However, if you for example wanted to set up specific deferred folder structures
+ for Nuke and Nuke X (both running the nuke engine), you need a finer granularity. This setting
+ can then be used to override the default behaviour of just passing the engine name. Instead, you
+ can pass any string into the deferred folder creation (for example 'nuke' and 'nuke_x' in the case
+ above). This parameter is also useful if you want to use deferred folder creation in
+ conjunction with launching of apps which do not have a toolkit engine defined - for these
+ app launch instances, the engine setting is left blank, and therefore no engine name is passed
+ into the deferred folder creation. In such cases you can utilize this parameter to control
+ the deferred folder creation.
+
+ You can specify multiple keywords using a comma as a delimiter (eg. 'nuke, nuke_x').
+ This will trigger folder creation for folders in your schema that have any
+ of these values in their deferred folder creation setting."
versions:
type: list
@@ -135,65 +132,78 @@ configuration:
values:
type: str
default_value: []
- description: "A list of strings that will be used to substitute for the {version} token
- in the values for the other settings for the instance of this app. For
- example, a value of ['2012', '2013', '2014'] for this setting and a value of
- 'Launch Maya {version}' for menu_name would result in the following command
- menu names being registered: Launch Maya 2012, Launch Maya 2013, Launch
- Maya 2014. The first version in the list will be considered the 'default'
- version if the engine running the app supports the concept. You can use pieces
- of the version if you wrap the parts in parenthesis like ['(7.0)v3', '(8.0)v1'].
- These pieces of the version string are available in the other settings via the
- {v0}, {v1}, {v2}, ... replacement tokens."
+ description:
+ "A list of strings that will be used to substitute for the {version} token
+ in the values for the other settings for the instance of this app. For
+ example, a value of ['2012', '2013', '2014'] for this setting and a value of
+ 'Launch Maya {version}' for menu_name would result in the following command
+ menu names being registered: Launch Maya 2012, Launch Maya 2013, Launch
+ Maya 2014. The first version in the list will be considered the 'default'
+ version if the engine running the app supports the concept. You can use pieces
+ of the version if you wrap the parts in parenthesis like ['(7.0)v3', '(8.0)v1'].
+ These pieces of the version string are available in the other settings via the
+ {v0}, {v1}, {v2}, ... replacement tokens."
skip_engine_instances:
type: list
allows_empty: True
values:
- type: str
+ type: str
default_value: []
- description: "A list of string names of engine instances to skip registering Software
- launcher commands for. For example, a value of ['tk-nukestudio'] for this
- setting would stop any Software entity launcher commands being registered
- with the engine that reference the 'tk-nukestudio' engine instance in that
- environment. This can be used to allow for an engine instance to be configured
- for a given environment without a launcher existing for it. This is useful
- in the case of Nuke Studio, where we want to allow for context changes into
- certain environments, but we only want the application to be launchable from
- a project environment. This setting only has an impact on Software entity
- launchers."
+ description:
+ "A list of string names of engine instances to skip registering Software
+ launcher commands for. For example, a value of ['tk-nukestudio'] for this
+ setting would stop any Software entity launcher commands being registered
+ with the engine that reference the 'tk-nukestudio' engine instance in that
+ environment. This can be used to allow for an engine instance to be configured
+ for a given environment without a launcher existing for it. This is useful
+ in the case of Nuke Studio, where we want to allow for context changes into
+ certain environments, but we only want the application to be launchable from
+ a project environment. This setting only has an impact on Software entity
+ launchers."
extra:
type: dict
- description: "ShotGrid engine specific extra values. These are defined per ShotGrid engine.
- Please look in the app documentation for more details."
+ description:
+ "ShotGrid engine specific extra values. These are defined per ShotGrid engine.
+ Please look in the app documentation for more details."
default_value: {}
hook_app_launch:
type: hook
- default_value: app_launch
- description: "Called to launch the application. This hook contains the code that does
- the actual execution of the launch command and parameters. If you have
- a custom launcher system in your studio, it can be handy to override
- Tank's default launch behaviour."
+ default_value: "{self}/app_launch.py"
+ description:
+ "Called to launch the application. This hook contains the code that does
+ the actual execution of the launch command and parameters. If you have
+ a custom launcher system in your studio, it can be handy to override
+ Tank's default launch behaviour."
hook_before_app_launch:
type: hook
- default_value: before_app_launch
- description: "This hook is called just before the hook_app_launch is used and can be
- useful if you don't want to modify the way applications are being launched
- (which is advanced usage and can be done by overriding the app_launch hook),
- but merely want to modify the environment before app launch. You may want
- to add additional pipeline paths, APIs or other things to the setup, or
- specify additional scripts etc to run."
+ default_value: "{self}/before_app_launch.py"
+ description:
+ "This hook is called just before the hook_app_launch is used and can be
+ useful if you don't want to modify the way applications are being launched
+ (which is advanced usage and can be done by overriding the app_launch hook),
+ but merely want to modify the environment before app launch. You may want
+ to add additional pipeline paths, APIs or other things to the setup, or
+ specify additional scripts etc to run."
hook_before_register_command:
type: hook
- default_value: before_register_command
- description: "This hook is called just before launcher command registration occurs.
- it can be used to alter the engine instance name associated with the
- launcher should that be required. This hook's methods are only called
- when Software entity launchers are being used."
+ default_value: "{self}/before_register_command.py"
+ description:
+ "This hook is called just before launcher command registration occurs.
+ it can be used to alter the engine instance name associated with the
+ launcher should that be required. This hook's methods are only called
+ when Software entity launchers are being used."
+
+ hook_launcher:
+ type: hook
+ default_value: "{self}/single_config_launcher.py"
+ description:
+ "This hook controls the method by which applications are collected
+ and launched."
# the Shotgun fields that this app needs in order to operate correctly
requires_shotgun_fields:
@@ -211,4 +221,8 @@ requires_engine_version:
supported_engines:
frameworks:
- - {"name": "tk-framework-shotgunutils", "version": "v5.x.x", "minimum_version": "v5.1.0"}
+ - {
+ "name": "tk-framework-shotgunutils",
+ "version": "v5.x.x",
+ "minimum_version": "v5.1.0",
+ }
diff --git a/python/tk_multi_launchapp/__init__.py b/python/tk_multi_launchapp/__init__.py
index c79c9c5..6f06f0c 100644
--- a/python/tk_multi_launchapp/__init__.py
+++ b/python/tk_multi_launchapp/__init__.py
@@ -8,5 +8,4 @@
# agreement to the Shotgun Pipeline Toolkit Source Code License. All rights
# not expressly granted therein are reserved by Shotgun Software Inc.
-from .single_config_launcher import SingleConfigLauncher
-from .software_entity_launcher import SoftwareEntityLauncher
+from .base_launcher import BaseLauncher
diff --git a/python/tk_multi_launchapp/base_launcher.py b/python/tk_multi_launchapp/base_launcher.py
index 3caebdc..881ee68 100644
--- a/python/tk_multi_launchapp/base_launcher.py
+++ b/python/tk_multi_launchapp/base_launcher.py
@@ -19,8 +19,10 @@
from .util import clear_dll_directory, restore_dll_directory
from .prepare_apps import prepare_launch_for_engine
+HookBaseClass = sgtk.get_hook_baseclass()
-class BaseLauncher(object):
+
+class BaseLauncher(HookBaseClass):
"""
Functionality to register engine commands that launch DCC
applications, as well as the business logic to perform the launch.
@@ -29,12 +31,10 @@ class BaseLauncher(object):
of sources.
"""
- def __init__(self):
+ def init(self):
"""
Initialize members
"""
- # Retrieve the TK Application from the current bundle
- self._tk_app = sgtk.platform.current_bundle()
# Store the current platform value
self._platform_name = (
@@ -45,6 +45,8 @@ def __init__(self):
else "windows"
)
+ return self
+
def _register_launch_command(
self,
app_menu_name,
@@ -111,7 +113,7 @@ def _register_launch_command(
"shotgun_publishedfile",
"shotgun_version",
]
- if self._tk_app.engine.environment.get("name") not in skip_environments:
+ if self.parent.engine.environment.get("name") not in skip_environments:
properties = {
"title": menu_name,
"short_name": command_name,
@@ -138,11 +140,11 @@ def launch_version(*args, **kwargs):
**kwargs
)
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Registering command %s to launch %s with args %s for engine %s"
% (command_name, app_path, app_args, app_engine)
)
- self._tk_app.engine.register_command(
+ self.parent.engine.register_command(
command_name, launch_version, properties
)
@@ -199,8 +201,8 @@ def _launch_app(
version_string = get_clean_version_string(version)
# run before launch hook
- self._tk_app.log_debug("Running before app launch hook...")
- self._tk_app.execute_hook(
+ self.parent.log_debug("Running before app launch hook...")
+ self.parent.execute_hook(
"hook_before_app_launch",
app_path=app_path,
app_args=app_args,
@@ -217,10 +219,10 @@ def _launch_app(
dll_directory_cache = clear_dll_directory()
try:
# Launch the application
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Launching executable '%s' with args '%s'" % (app_path, app_args)
)
- result = self._tk_app.execute_hook(
+ result = self.parent.execute_hook(
"hook_app_launch",
app_path=app_path,
app_args=app_args,
@@ -233,35 +235,35 @@ def _launch_app(
finally:
restore_dll_directory(dll_directory_cache)
- self._tk_app.log_debug("Hook tried to launch '%s'" % launch_cmd)
+ self.parent.log_debug("Hook tried to launch '%s'" % launch_cmd)
if return_code != 0:
# some special logic here to decide how to display failure feedback
if app_engine == "tk-shotgun":
# for the shotgun engine, use the log info in order to
# get the proper html formatting
- self._tk_app.log_info(
+ self.parent.log_info(
"Failed to launch application! "
"This is most likely because the path is not set correctly."
"The command that was used to attempt to launch is '%s'. "
"
Click here to learn "
"more about how to setup your app launch configuration."
- % (launch_cmd, self._tk_app.HELP_DOC_URL)
+ % (launch_cmd, self.parent.HELP_DOC_URL)
)
- elif self._tk_app.engine.has_ui:
+ elif self.parent.engine.has_ui:
# got UI support. Launch dialog with nice message
from ..not_found_dialog import show_path_error_dialog
- show_path_error_dialog(self._tk_app, launch_cmd)
+ show_path_error_dialog(self.parent, launch_cmd)
else:
# traditional non-ui environment without any html support.
- self._tk_app.log_error(
+ self.parent.log_error(
"Failed to launch application! This is most likely because "
"the path is not set correctly. The command that was used "
"to attempt to launch is '%s'. To learn more about how to "
"set up your app launch configuration, see the following "
- "documentation: %s" % (launch_cmd, self._tk_app.HELP_DOC_URL)
+ "documentation: %s" % (launch_cmd, self.parent.HELP_DOC_URL)
)
else:
@@ -299,12 +301,12 @@ def _register_event_log(self, menu_name, app_engine, ctx, command_executed):
launch the DCC.
"""
meta = {}
- meta["core"] = self._tk_app.sgtk.version
+ meta["core"] = self.parent.sgtk.version
meta["engine"] = "%s %s" % (
- self._tk_app.engine.name,
- self._tk_app.engine.version,
+ self.parent.engine.name,
+ self.parent.engine.version,
)
- meta["app"] = "%s %s" % (self._tk_app.name, self._tk_app.version)
+ meta["app"] = "%s %s" % (self.parent.name, self.parent.version)
meta["launched_engine"] = app_engine
meta["command"] = command_executed
# In Python 3 and certain flavors of Python 2, the sys.platform value under Linux
@@ -320,9 +322,9 @@ def _register_event_log(self, menu_name, app_engine, ctx, command_executed):
)
if ctx.task:
meta["task"] = ctx.task["id"]
- desc = "%s %s: %s" % (self._tk_app.name, self._tk_app.version, menu_name)
+ desc = "%s %s: %s" % (self.parent.name, self.parent.version, menu_name)
sgtk.util.create_event_log_entry(
- self._tk_app.sgtk, ctx, "Toolkit_App_Startup", desc, meta
+ self.parent.sgtk, ctx, "Toolkit_App_Startup", desc, meta
)
def _launch_callback(
@@ -351,26 +353,26 @@ def _launch_callback(
this launch command.
"""
# Verify a Project is defined in the context.
- if self._tk_app.context.project is None:
+ if self.parent.context.project is None:
raise TankError(
"Your context does not have a project defined. Cannot continue."
)
# Extract an entity type and id from the context.
- entity_type = self._tk_app.context.project["type"]
- entity_id = self._tk_app.context.project["id"]
+ entity_type = self.parent.context.project["type"]
+ entity_id = self.parent.context.project["id"]
# if there is an entity then that takes precedence
- if self._tk_app.context.entity:
- entity_type = self._tk_app.context.entity["type"]
- entity_id = self._tk_app.context.entity["id"]
+ if self.parent.context.entity:
+ entity_type = self.parent.context.entity["type"]
+ entity_id = self.parent.context.entity["id"]
# and if there is a task that is even better
- if self._tk_app.context.task:
- entity_type = self._tk_app.context.task["type"]
- entity_id = self._tk_app.context.task["id"]
+ if self.parent.context.task:
+ entity_type = self.parent.context.task["type"]
+ entity_id = self.parent.context.task["id"]
- if len(self._tk_app.sgtk.roots) == 0:
+ if len(self.parent.sgtk.roots) == 0:
# configuration doesn't have any filesystem roots defined
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Configuration does not have any filesystem roots defined. "
"Skipping folder creation."
)
@@ -379,13 +381,13 @@ def _launch_callback(
# Do the folder creation. If there is a specific defer keyword,
# this takes precedence. Otherwise, use the engine name for the
# DCC application by default.
- defer_keyword = self._tk_app.get_setting("defer_keyword") or app_engine
+ defer_keyword = self.parent.get_setting("defer_keyword") or app_engine
try:
- self._tk_app.log_debug(
+ self.parent.log_debug(
"Creating folders for %s %s. Defer keyword: '%s'"
% (entity_type, entity_id, defer_keyword)
)
- self._tk_app.sgtk.create_filesystem_structure(
+ self.parent.sgtk.create_filesystem_structure(
entity_type, entity_id, engine=defer_keyword
)
except sgtk.TankError as err:
@@ -399,7 +401,7 @@ def _launch_callback(
app_engine,
app_path,
app_args,
- self._tk_app.context,
+ self.parent.context,
version,
file_to_open,
software_entity,