Open from publish in tk-multi-workfiles2 scene_operation hooks

In the tk-multi-workfiles2 hooks (specifically scene_operation_tk-maya.py), how can I tell if I’m opening a file from an existing publish versus opening an existing work file. I want to take some action only if the artist is opening an existing publish, not if they’re opening an existing workfile.

Any thoughts?

2 Likes

Hi Rob

Welcome to the forums!
I can think of a couple of ways to do this within the scene operations hook:

# get the publish template Workfiles2 is currently configured to use.
publish_template = self.parent.get_template("template_publish")

if publish_template.validate(file_path):
    # we have a published file

Edit the above method would not consistently work in this situation due to the current workfiles settings not being reflective of the environment it’s about to change into.
Instead it would be better to do:

app_settings = sgtk.platform.find_app_settings(self.parent.engine.name,
                                               "tk-multi-workfiles2",
                                               self.parent.sgtk,
                                               context)

if app_settings:
    # its possible to have multiple instances of an app in a given environment
    # but we are assuming here that there is only one instance of workfiles2, so we take the first one.
    publish_template_string = app_settings[0]["settings"]["template_publish"]
    publish_template = self.sgtk.templates[publish_template_string]
    self.logger.info(publish_template)

Or

publishedFiles = sgtk.util.find_publish(self.sgtk, [file_path])

Cheers
Phil

1 Like

Hi Philip,

Thanks for the reply!

Just wondering, does the file_path argument that comes into the execute() method contain the path to the published file, or to the file that was copied from that published file? When I output some debug messages from the hook,. it seems to be the latter.

There is a line above in the script editor output in Maya that says:
// Debug: Shotgun tk-multi-workfiles2: Copying file 'XXX' to 'YYY' via hook //

So I think what is passed to the hook is the YYY file (destination of the copy, in the work area).

1 Like

Ah good point, I’ll take another look and see if I can think of anything.

2 Likes

OK I’ve got another idea in addition to what I suggested previously.

What you could do is take over the copy_file.py hook, as this will be called when the file gets copied during the open. Then in this hook you could store an env var with the source and dest paths, something like:

import os
# combine them into one env var or store them as separate env vars.
os.envion["PUBTOWORK"] = os.path.pathsep.join([source_path, target_path])

Then in the scene operations hook you can retrieve the env var, check if the target_path matches the file you’re going to open and then you know which publish it came from.

pub_to_work = os.envion.get("PUBTOWORK")

if pub_to_work:

    source, target = combined.split(os.path.pathsep)

    if file_path == target:
        # The file we are opening matches that which was previously copied,
        # now find which publish comes from the source

       # We need to grab the publish template settings so we can check the source path against 
       # the publish template, to ensure it is a publish. We're not using self.parent.get_template
       # as we might be in the middle of switching environments and the current settings
       # might not be reflective of the environment we are going to into.
       app_settings = sgtk.platform.find_app_settings(self.parent.engine.name,
                                                       "tk-multi-workfiles2",
                                                       self.parent.sgtk,
                                                       context)

        if app_settings:
            # its possible to have multiple instances of an app in a given environment
            # but we are assuming here that there is only one instance of workfiles2, 
            # so we take the first one.
            publish_template_string = app_settings[0]["settings"]["template_publish"]
            publish_template = self.sgtk.templates[publish_template_string]
            self.logger.info("Publish template found: %s" % publish_template)

            publish_template = self.parent.get_template("template_publish")
            if publish_template.validate(file_path):
                # we have a published file
                ...

I think that would work?

Thanks
Phil

2 Likes

Oooh that’s a nice idea, to take over copy_file.py.

One question - will this hook also be called if a user tries to open a file (and thus copy the file) from another user’s workspace/sandbox? I guess the way around that is to set the PUBTOWORK env var if the source path validates against a publish template, right?

1 Like

Yeah I think there would be other times that this hook would be called, but hopefully by

  1. Checking that the file you are opening matches that of the target path supplied in the env var, should help protect against old env var data or other copies.
  2. Checking that the source path is a publish. (which you could do at the stage of copying but in my code above it’s performing that check at open time instead.)

I’m not a 100% confident I’ve thought of everything, but it seems like it should be reliable enough.

1 Like

I’ll give it a whirl and report back!

2 Likes

I get an error at this line:

publish_template = self.parent.app.get_template("template_publish")

When accessing the copy_file hook. It says:

AttributeError: 'MultiWorkFiles' object has no attribute 'app'

Is there another way to access the publish template from a workfiles hook?

Ah sorry about that, should have been just self.parent.get_template("template_publish")
Just tested that line here and it works, I’ve updated my posts above.

Hmmm…that returns None for some reason. tk-multi-workfiles2.yml looks like this:

# ---- Maya

# asset_step
settings.tk-multi-workfiles2.maya.asset_step:
  template_publish: maya_asset_publish
  template_publish_area: asset_publish_area_maya
  template_work: maya_asset_work
  template_work_area: asset_work_area_maya
  hook_scene_operation: "{config}/tk-multi-workfiles2/scene_operation_{engine_name}.py"
  hook_copy_file: "{config}/tk-multi-workfiles2/copy_file.py"

Seems strange that it would do that. My copy_file.py looks like:

def execute(self, source_path, target_path, **kwargs):
    """
    Main hook entry point

    :source_path:   String
                    Source file path to copy

    :target_path:   String
                    Target file path to copy to
    """

    publish_template = self.parent.get_template("template_publish")
    if publish_template.validate(source_path):
        # We're dealing with a published file, so set the env var
        os.environ["PUBTOWORK"] = os.path.pathsep.join([source_path, target_path])

    # create the folder if it doesn't exist
    dirname = os.path.dirname(target_path)
    if not os.path.isdir(dirname):
        old_umask = os.umask(0)
        os.makedirs(dirname, 0777)
        os.umask(old_umask)

    shutil.copy(source_path, target_path)

Ah, I think I might know why that is.
I suspect this is because the context hasn’t changed at this point and you’re switching from say a project environment where there is no template set, to a asset_step where there is a template set.

I won’t have chance to test it tonight, but maybe you’ll need to grab the template setting using the sgtk.platform.find_app_settings API method instead?

When I was testing I was already in the right environment, so I didn’t think of that, sorry!

I’ll update the example tomorrow once I’ve tested.

1 Like

Hi Rob

I’ve update the example in this post.

The bits I’ve added are:

app_settings = sgtk.platform.find_app_settings(self.parent.engine.name,
                                               "tk-multi-workfiles2",
                                               self.parent.sgtk,
                                               context)

if app_settings:
    # its possible to have multiple instances of an app in a given environment
    # but we are assuming here that there is only one instance of workfiles2, so we take the first one.
    publish_template_string = app_settings[0]["settings"]["template_publish"]
    publish_template = self.sgtk.templates[publish_template_string]
    self.logger.info(publish_template)

Hi Philip,

Finally got through this thanks to your help! The copy_file hook looks like this:

def execute(self, source_path, target_path, **kwargs):
    """
    Main hook entry point

    :source_path:   String
                    Source file path to copy

    :target_path:   String
                    Target file path to copy to
    """
    engine = sgtk.platform.current_engine()
    tk = engine.sgtk
    # Get context from the published file path
    context = tk.context_from_path(source_path)
   
    # Get settings from yml
    settings = sgtk.platform.find_app_settings(engine.instance_name, self.parent.instance_name, tk, context)

    # Get publish template from the settings yml
    publish_template_name = settings[0]["settings"].get("template_publish")
    publish_template = tk.templates[publish_template_name]
    if publish_template.validate(source_path):
        # We're dealing with a published file, so set the env var
        os.environ["PUBTOWORK"] = os.path.pathsep.join([source_path, target_path])

    # create the folder if it doesn't exist
    dirname = os.path.dirname(target_path)
    if not os.path.isdir(dirname):
        old_umask = os.umask(0)
        os.makedirs(dirname, 0777)
        os.umask(old_umask)

    shutil.copy(source_path, target_path)

Just in case anyone else was looking to do something similar.

Thanks again!

2 Likes

Nice! thanks for sharing Rob

On thought on this though, is if you are performing the publish check in the copy hook, are you also performing that check in the scene operations hook?
How do you catch the situations when an artist opens the publish file directly, as the copy_hook wouldn’t be involved?
Would be awesome to see the the scene operations portion to help complete the example.

Cheers
Phil

1 Like