Skip to main content

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

note

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.
note

In case of multiple integrations loaded, the priority provided in the integration will drive the order the environment variables will be manipulated.