Using Shotgun to distribute software plugins

[This post is part of a series of articles about working from home in Shotgun.]

When using a distributed pipeline setup, with users working in remote locations, there can arise a need to be able to not only distribute your Toolkit configuration and your work, but also any other tools/plugins that usually sit outside of the Toolkit pipeline.

This post aims to provide an example of how you can set up a way to distribute your Software plugins along with your Toolkit config. It will focus on the distribution part rather than the setup of the plugins, and some plugins which require running an installer might be hard to setup.
However, for plugins that just require a folder to be downloaded and included in some way to your environment, this should work well enough.

Please note that the code provided in this example is not tested in production and is not guaranteed to work, it is intended as an example that can be built upon.

Overview

The process described below will set up a custom entity on your Shotgun site, where you will upload your plugin payload as a zip. Your Toolkit configuration will then contain a hook that will be run when a user tries to launch software, which will check for plugins and download and set up any that are found on your Shotgun site.

Steps

  1. First, you need to enable your custom entity that will represent the software plugins. Navigate to the site preferences and enable a CustomNonProjectEntity and create a new page to view it on:


  2. Create a new File field called Payload on your new entity type.


    Feel free to create a new entity to test with, but don’t upload anything to it yet. Also, the Software field shown will be created in the next step.

  3. Navigate to your Software entity page, and create a new multi entity field called Software Plugins (field code sg_software_plugin) which links to your new custom entity.
    Software
    This relationship will allow us to know what plugins are required when launching certain software.

  4. Now you need to add a hook to your config to download these plugins when launching. Copy the before_app_launch.py hook from the tk-multi-launchapp to your config’s hooks folder:
    hooks_copy

  5. Modify your app launch environment settings to use this hook, and also request the sg_software_plugin field to be included with the Software entity that gets passed to the hook.

    software_entity_extra_fields: [sg_software_plugins]
    hook_before_app_launch: "{config}/tk-multi-launchapp/before_app_launch.py"
    

    Advanced/tk-config-default2:


    Basic/tk-config-basic:

  6. Next replace the contents of your before_app_launch.py file with this: before_app_launch.py (7.8 KB)
    The code is commented so I won’t go through it line by line here, but essentially what it does is:

    1. Finds the plugins associated with the Software entity.
    2. Before downloading, it will check to see if that version of the plugin has already been downloaded.
    3. If not it will download and unzip it, to a folder in the Shotgun cache ({Shotgun Cache}/{your site}/site/tm-launchapp/plugins/), or you can specify a plugin root folder with the SOFTWARE_PLUGIN_ROOT environment variable.
    4. It expects each plugin zip to contain a single folder which contains the plugin, and will rename it to be the id of the attachment.
    5. It then looks for an sg_setup.py file inside the root of the plugin folder which will be called to setup the plugin. Each plugin is responsible for its own setup.
  7. Preparing a plugin payload. As mentioned above all the plugin files must be contained within a single folder, and that folder must contain a sg_setup.py file. Here is a sg_setup.py file that contains only the required code: sg_setup.py (242 Bytes). You will need to implement code in there that enables the plugin to be used by the software.

  8. Zip up your plugin and upload it to the payload field on your Shotgun Plugin entity. Ensure that your plugin has been added to a Software as well via the software field.

And that is everything you need to do.

Real-world example

Whilst I was testing, I picked the first free Maya plugin I could find on the internet and attempted to set this up. The plugin I picked contained mostly python files and an install.mel script. I decided to replicate the behavior of the install script and implement it into a userSetup.py script (which Maya runs on startup.) I then implemented the following code in the sg_setup.py so that the userSetup.py would be run on startup.

import sys
import os
import sgtk

def execute(
    plugin_path,
    software_plugin,
    app_path,
    app_args,
    version,
    engine_name,
    software_entity,
    **kwargs
):
    # There may be a better way of doing this, but you can't use
    # `__file__` in the `userSetup.py` so we are getting the current
    # plugin location here and setting it in an env var so that the
    # `userSetup.py` can access it when it runs.
    os.environ["STUDIO_LIBRARY_PATH"] = plugin_path
    # Append the root plugin path to the PYTHONPATH env var
    # so that the userSetup.py file will be run when Maya 
    # launches.
    sgtk.util.append_path_to_env_var("PYTHONPATH", plugin_path)

My plugin before being zipped then looked like this:

There are many other approaches you could use, and ways to improve this example:

  • Pulling your plugins from a location other than Shotgun.
  • Showing a splash screen whilst it downloads so the user knows why it’s taking a while.
  • Bundling the plugins in a framework, uploading the framework to Shotgun, and then referencing the framework with a Shotgun descriptor. Then you could call the framework from the hook. This approach would mean you wouldn’t need to handle the downloading plugins your self, as this would be done when the config is bootstrapped.

Feel free to share any suggestions or approaches you may have!

8 Likes