Connect plugin
All integrations that want to be discovered and installable by connect have to be defined as connect plugin, specifically
by the hook in the hook
plugin folder.
Application launcher
Although a DCC integration can be written to provide its own logic for configuring the environment (see RV integration), it is recommended to utilise the Connect application launcher and configure it through the launch configuration. This also gives the ability to make overrides and customisations through the Connect extensions subsystem.
Connect plugin hook
The hook file is a python file that allows the integration to be discovered by Connect. It must contain the register
method which is picked up by the ftrack Python API, as Connect adds the ´hook´ folder to the FTRACK_EVENT_PLUGIN_PATH.
In the following snippet you can see the default Maya Connect hook implementation. The on_discover_integration
replies back to
the discovery event sent out by Connect application launcher modules, and on_launch_integration
is used to set up all the
variables needed for maya to find the integration code.
# :coding: utf-8
# :copyright: Copyright (c) 2024 ftrack
import os
import ftrack_api
import logging
import functools
from ftrack_utils.version import get_connect_plugin_version
# The name of the integration, should match name in launcher.
NAME = 'framework-maya'
logger = logging.getLogger(__name__)
cwd = os.path.dirname(__file__)
connect_plugin_path = os.path.abspath(os.path.join(cwd, '..'))
# Read version number from __version__.py
__version__ = get_connect_plugin_version(connect_plugin_path)
python_dependencies = os.path.join(connect_plugin_path, 'dependencies')
def on_discover_integration(session, event):
data = {
'integration': {
'name': NAME,
'version': __version__,
}
}
return data
def on_launch_integration(session, event):
'''Handle application launch and add environment to *event*.'''
launch_data = {'integration': event['data']['integration']}
discover_data = on_discover_integration(session, event)
for key in discover_data['integration']:
launch_data['integration'][key] = discover_data['integration'][key]
integration_version = event['data']['application']['version'].version[0]
logger.info('Launching integration v{}'.format(integration_version))
if not launch_data['integration'].get('env'):
launch_data['integration']['env'] = {}
bootstrap_path = os.path.join(connect_plugin_path, 'resource', 'bootstrap')
logger.info('Adding {} to PYTHONPATH'.format(bootstrap_path))
launch_data['integration']['env'][
'PYTHONPATH.prepend'
] = os.path.pathsep.join([python_dependencies, bootstrap_path])
launch_data['integration']['env']['MAYA_SCRIPT_PATH'] = bootstrap_path
launch_data['integration']['env']['FTRACK_MAYA_VERSION'] = str(
integration_version
)
selection = event['data'].get('context', {}).get('selection', [])
if selection:
task = session.get('Context', selection[0]['entityId'])
launch_data['integration']['env']['FTRACK_CONTEXTID.set'] = task['id']
return launch_data
def register(session):
'''Subscribe to application launch events on *registry*.'''
if not isinstance(session, ftrack_api.session.Session):
return
handle_discovery_event = functools.partial(
on_discover_integration, session
)
session.event_hub.subscribe(
'topic=ftrack.connect.application.discover and '
'data.application.identifier=maya*'
' and data.application.version >= 2021',
handle_discovery_event,
priority=40,
)
handle_launch_event = functools.partial(on_launch_integration, session)
session.event_hub.subscribe(
'topic=ftrack.connect.application.launch and '
'data.application.identifier=maya*'
' and data.application.version >= 2021',
handle_launch_event,
priority=40,
)
logger.info(
'Registered {} integration v{} discovery and launch.'.format(
NAME, __version__
)
)
This hook is composed by 3 important pieces.
- 2 listeners to discover and launch
- 1 register function to subscribe with listener callbacks.
Listeners
Each integration will have to provide two event listeners hooked to the same function.
Each of this will have to provide a filter for the application to be launched, optional, but suggested is to provide a lower/higher limit based on the application version for this integration.
In case more than one integration has to be loaded in a given order is suggested to provide them with an increasing priority version.
The discovery one:
session.event_hub.subscribe(
'topic=ftrack.connect.application.discover and '
'data.application.identifier=an_application*'
' and data.application.version >= 2021',
handle_event, priority=40
)
The above event will be emitted during the discovery cycle of the applications , which happens when the correct context gets selected. This is used to check the version and if the integration is available.
And the launch one:
session.event_hub.subscribe(
'topic=ftrack.connect.application.launch and '
'data.application.identifier=an_application*'
' and data.application.version >= 2021',
handle_event, priority=40
)
The above event will be emitted during the launch cycle of the applications and will be used to parse and inject the environment variables defined during the application’s startup.
Discover Function
The discover function will be the one to provide to the applications the right environment where to pick the required files.
The bare minimum amount of data it should return in order to be discovered as working integrations is
{
'integration': {
"name": '<name-of-the-integration>',
'version': '<the.integration.version>'
}
}
where a fully formed integrations would provide also entry point for the environment variables:
data = {
'integration': {
"name": 'ftrack-example-integration',
'version': '0.0.0',
'env': {
'FTRACK_EVENT_PLUGIN_PATH.prepend': hook_path,
'PYTHONPATH.prepend': os.path.pathsep.join([python_dependencies]),
'FTRACK_CONTEXTID.set': task['id'],
}
}
}
Managing environment variables
Each integration can express a set of environment variables and operations to be performed when handled by the application launcher.
the formatting of envs is composed by:
<$ENVIRONMENT> . <OPERATION>
for example:
'PYTHONPATH.append': '<some file system path>'
Environment operations
If not provided, the default operation for environment will be append
- prepend : The value of the environment will be prepended.
- append : The value of the environment will be appended.
- set: The given environment will be set with the given value.
- pop: The value of the environment variable will be removed.
- unset: The environment value will be unset.
In case of multiple integrations loaded, the priority provided in the integration will drive the order the environment variables will be manipulated.