Beispiel #1
0
    def __validate(self, value, validate_transforms):
        """
        Test if a value is valid for this key.

        :param value: Value to test
        :param validate_transforms: If true, then validate that transforms that mutate the
                                    value of a key are valid and can be applied.
        :returns: True if valid, false if not.
        """
        u_value = value
        if not isinstance(u_value, six.text_type):
            # handle non-ascii characters correctly by
            # decoding to unicode assuming utf-8 encoding
            u_value = value.decode("utf-8")

        if self._filter_regex_u:
            # first check our std filters. These filters are negated
            # so here we are checking that there are occurances of
            # that pattern in the string
            if self._filter_regex_u.search(u_value):
                self._last_error = (
                    "%s Illegal value '%s' does not fit filter_by '%s'"
                    % (self, value, self.filter_by)
                )
                return False

        elif self._custom_regex_u:
            # check for any user specified regexes
            if self._custom_regex_u.match(u_value) is None:
                self._last_error = (
                    "%s Illegal value '%s' does not fit filter_by '%s'"
                    % (self, value, self.filter_by)
                )
                return False

        # check subset regex
        if self._subset_regex and validate_transforms:
            regex_match = self._subset_regex.match(u_value)
            if regex_match is None:
                self._last_error = (
                    "%s Illegal value '%s' does not fit "
                    "subset expression '%s'" % (self, value, self.subset)
                )
                return False

            # validate that the formatting can be applied to the input value
            if self._subset_format:
                try:
                    # perform the formatting in unicode space to cover all cases
                    six.ensure_text(self._subset_format).format(*regex_match.groups())
                except Exception as e:
                    self._last_error = (
                        "%s Illegal value '%s' does not fit subset '%s' with format '%s': %s"
                        % (self, value, self.subset, self.subset_format, e)
                    )
                    return False

        return super(StringKey, self).validate(value)
    def execute_action(self, name, params, sg_publish_data):
        """
        Execute a given action. The data sent to this be method will
        represent one of the actions enumerated by the generate_actions method.

        :param name: Action name string representing one of the items returned
                     by generate_actions.
        :param params: Params data, as specified by generate_actions.
        :param sg_publish_data: Shotgun data dictionary with all the standard
                                publish fields.
        """
        app = self.parent
        app.log_debug("Execute action called for action %s. "
                      "Parameters: %s. Publish Data: %s" %
                      (name, params, sg_publish_data))

        # resolve path
        # toolkit uses utf-8 encoded strings internally and the Photoshop API expects unicode
        # so convert the path to ensure filenames containing complex characters are supported
        path = six.ensure_text(self.get_publish_path(sg_publish_data))

        if not os.path.exists(path):
            raise Exception("File not found on disk - '%s'" % path)

        if name == _OPEN_FILE:
            self._open_file(path, sg_publish_data)
        if name == _ADD_AS_A_LAYER:
            self._place_file(path, sg_publish_data)
    def _as_string(self, value):
        """
        Converts the given value to a string representation.

        :param value: value of any type to convert. Value is never None.
        :returns: string representation for this object.
        """
        str_value = value if isinstance(value,
                                        six.string_types) else str(value)

        if self._subset_regex:
            # process substring computation.
            # we want to do this in unicode.

            if isinstance(str_value, six.binary_type):
                # convert to unicode
                input_is_utf8 = True
                value_to_convert = str_value.decode("utf-8")
            else:
                # already unicode
                input_is_utf8 = False
                value_to_convert = str_value

            # now perform extraction and concat
            match = self._subset_regex.match(value_to_convert)
            if match is None:
                # no match. return empty string
                # validate should prevent this from happening
                resolved_value = u""

            elif self._subset_format:
                # we have an explicit format string we want to apply to the
                # match. Do the formatting as unicode.
                resolved_value = six.ensure_text(
                    self._subset_format).format(*match.groups())

            else:
                # we have a match object. concatenate the groups
                resolved_value = "".join(match.groups())

            # resolved value is now unicode. Convert it
            # so that it is consistent with input
            if isinstance(resolved_value, six.text_type) and input_is_utf8:
                # input was utf-8, regex resut is unicode, cast it back
                str_value = resolved_value.encode("utf-8")
            else:
                str_value = resolved_value

        return str_value
Beispiel #4
0
    def execute_action(self, name, params, sg_data):
        """
        Execute a given action. The data sent to this be method will
        represent one of the actions enumerated by the generate_actions method.

        :param name: Action name string representing one of the items returned
                     by generate_actions.
        :param params: Params data, as specified by generate_actions.
        :param sg_data: Shotgun data dictionary with all the standard
                                publish fields.
        """
        app = self.parent
        app.logger.debug(
            "Execute action called for action %s. "
            "Parameters: %s. Publish Data: %s" % (name, params, sg_data)
        )

        # This hook only implements the add to comp and project logic, fall back to the
        # base class for anything else.
        if name in [_ADD_TO_COMP, _ADD_TO_PROJECT]:
            # resolve path
            # toolkit uses utf-8 encoded strings internally and the After Effects API expects unicode
            # so convert the path to ensure filenames containing complex characters are supported
            path = six.ensure_text(self.get_publish_path(sg_data))

            if self.parent.engine.is_adobe_sequence(path):
                frame_range = self.parent.engine.find_sequence_range(path)
                if frame_range:
                    glob_path = re.sub(
                        r"[\[]?([#@]+|%0\d+d)[\]]?", "*{}".format(frame_range[0]), path
                    )
                    for each_path in sorted(glob.glob(glob_path)):
                        path = each_path
                        break

            if not os.path.exists(path):
                raise Exception("File not found on disk - '%s'" % path)

            if name == _ADD_TO_COMP:
                self._add_to_comp(path)
            if name == _ADD_TO_PROJECT:
                self.parent.engine.import_filepath(path)
        else:
            try:
                HookBaseClass.execute_action(self, name, params, sg_data)
            except AttributeError:
                # base class doesn't have the method, so ignore and continue
                pass
Beispiel #5
0
    def finalize(self, settings, item):
        """
        Execute the finalization pass. This pass executes once
        all the publish tasks have completed, and can for example
        be used to version up files.

        :param settings: Dictionary of Settings. The keys are strings, matching
            the keys returned in the settings property. The values are `Setting`
            instances.
        :param item: Item to process
        """
        publisher = self.parent
        thumb = item.get_thumbnail_as_path()
        upload_thumb = True
        version = item.properties["sg_version_data"]
        finalize_tasks = item.properties.get("version_finalize")

        if version and finalize_tasks:

            if finalize_tasks["update"]:
                publisher.shotgun.update("Version", version["id"],
                                         finalize_tasks["update"])

            if finalize_tasks["upload"]:
                for field, path in finalize_tasks["upload"].iteritems():
                    self.logger.info("Uploading content...")

                    # on windows, ensure the path is utf-8 encoded to avoid issues with
                    # the shotgun api
                    if sgtk.util.is_windows():
                        upload_path = six.ensure_text(path)
                    else:
                        upload_path = path

                    publisher.shotgun.upload("Version", version["id"],
                                             upload_path, field)
                    upload_thumb = False

        if upload_thumb:
            # only upload thumb if we are not uploading the content. with
            # uploaded content, the thumb is automatically extracted.
            self.logger.info("Uploading thumbnail...")
            publisher.shotgun.upload_thumbnail("Version", version["id"], thumb)
Beispiel #6
0
    def _get_latest_by_pattern(self, pattern):
        """
        Returns a descriptor object that represents the latest
        version, but based on a version pattern.

        :param pattern: Version patterns are on the following forms:
            - v1.2.3 (can return this v1.2.3 but also any forked version under, eg. v1.2.3.2)
            - v1.2.x (examples: v1.2.4, or a forked version v1.2.4.2)
            - v1.x.x (examples: v1.3.2, a forked version v1.3.2.2)
            - v1.2.3.x (will always return a forked version, eg. v1.2.3.2)
        :returns: IODescriptorGitTag object
        """
        try:
            # clone the repo, list all tags
            # for the repository, across all branches
            commands = ["tag"]
            git_tags = six.ensure_text(
                self._tmp_clone_then_execute_git_commands(commands)
            ).split("\n")

        except Exception as e:
            raise TankDescriptorError(
                "Could not get list of tags for %s: %s" % (self._path, e)
            )

        if len(git_tags) == 0:
            raise TankDescriptorError(
                "Git repository %s doesn't have any tags!" % self._path
            )

        latest_tag = self._find_latest_tag_by_pattern(git_tags, pattern)
        if latest_tag is None:
            raise TankDescriptorError(
                "'%s' does not have a version matching the pattern '%s'. "
                "Available versions are: %s"
                % (self.get_system_name(), pattern, ", ".join(git_tags))
            )

        return latest_tag
Beispiel #7
0
    def execute_action(self, name, params, sg_publish_data):
        """
        Execute a given action. The data sent to this be method will
        represent one of the actions enumerated by the generate_actions method.

        :param name: Action name string representing one of the items returned by generate_actions.
        :param params: Params data, as specified by generate_actions.
        :param sg_publish_data: Shotgun data dictionary with all the standard publish fields.
        :returns: No return value expected.
        """
        app = self.parent
        app.log_debug(
            "Execute action called for action %s. "
            "Parameters: %s. Publish Data: %s" % (name, params, sg_publish_data)
        )

        # resolve path
        # toolkit uses utf-8 encoded strings internally and the 3dsmax API expects unicode
        # so convert the path to ensure filenames containing complex characters are supported
        path = six.ensure_text(self.get_publish_path(sg_publish_data))

        # If this is an Alembic cache, then we can import that.
        if path.lower().endswith(".abc"):
            # Note that native Alembic support is only available in Max 2016+.
            if app.engine._max_version_to_year(app.engine._get_max_version()) >= 2016:
                self._import_alembic(path)
            else:
                app.log_warning(
                    "Alembic imports are not available in Max 2015, skipping."
                )
        elif name == "merge":
            self._merge(path, sg_publish_data)
        elif name == "xref_scene":
            self._xref_scene(path, sg_publish_data)
        elif name == "texture_node":
            self._create_texture_node(path, sg_publish_data)
Beispiel #8
0
    def publish(self, settings, item):
        """
        Executes the publish logic for the given item and settings.

        :param settings: Dictionary of Settings. The keys are strings, matching
            the keys returned in the settings property. The values are `Setting`
            instances.
        :param item: Item to process
        """

        publisher = self.parent
        path = item.properties["path"]

        # allow the publish name to be supplied via the item properties. this is
        # useful for collectors that have access to templates and can determine
        # publish information about the item that doesn't require further, fuzzy
        # logic to be used here (the zero config way)
        publish_name = item.properties.get("publish_name")
        if not publish_name:

            self.logger.debug("Using path info hook to determine publish name.")

            # use the path's filename as the publish name
            path_components = publisher.util.get_file_path_components(path)
            publish_name = path_components["filename"]

        self.logger.debug("Publish name: %s" % (publish_name,))

        self.logger.info("Creating Version...")
        version_data = {
            "project": item.context.project,
            "code": publish_name,
            "description": item.description,
            "entity": self._get_version_entity(item),
            "sg_task": item.context.task,
        }

        if "sg_publish_data" in item.properties:
            publish_data = item.properties["sg_publish_data"]
            version_data["published_files"] = [publish_data]

        if settings["Link Local File"].value:
            version_data["sg_path_to_movie"] = path

        # log the version data for debugging
        self.logger.debug(
            "Populated Version data...",
            extra={
                "action_show_more_info": {
                    "label": "Version Data",
                    "tooltip": "Show the complete Version data dictionary",
                    "text": "<pre>%s</pre>" % (pprint.pformat(version_data),),
                }
            },
        )

        # Create the version
        version = publisher.shotgun.create("Version", version_data)
        self.logger.info("Version created!")

        # stash the version info in the item just in case
        item.properties["sg_version_data"] = version

        thumb = item.get_thumbnail_as_path()

        if settings["Upload"].value:
            self.logger.info("Uploading content...")

            # on windows, ensure the path is utf-8 encoded to avoid issues with
            # the shotgun api
            if sgtk.util.is_windows():
                upload_path = six.ensure_text(path)
            else:
                upload_path = path

            self.parent.shotgun.upload(
                "Version", version["id"], upload_path, "sg_uploaded_movie"
            )
        elif thumb:
            # only upload thumb if we are not uploading the content. with
            # uploaded content, the thumb is automatically extracted.
            self.logger.info("Uploading thumbnail...")
            self.parent.shotgun.upload_thumbnail("Version", version["id"], thumb)

        self.logger.info("Upload complete!")
Beispiel #9
0
    def publish(self, settings, item):
        """
        Executes the publish logic for the given item and settings.

        :param settings: Dictionary of Settings. The keys are strings, matching
            the keys returned in the settings property. The values are `Setting`
            instances.
        :param item: Item to process
        """

        publisher = self.parent
        path = item.properties["path"]

        # allow the publish name to be supplied via the item properties. this is
        # useful for collectors that have access to templates and can determine
        # publish information about the item that doesn't require further, fuzzy
        # logic to be used here (the zero config way)
        publish_name = item.properties.get("publish_name")
        if not publish_name:

            self.logger.debug("Using path info hook to determine publish name.")

            # use the path's filename as the publish name
            path_components = publisher.util.get_file_path_components(path)
            publish_name = path_components["filename"]

        self.logger.debug("Publish name: %s" % (publish_name,))

        self.logger.info("Creating Version...")



        def get_path_to_frames():

            change_folder = path.replace('\mov', '/fullres')
            change_file_extension = change_folder.replace('.mov', '.####.exr')
            return change_file_extension



        def get_userID():
            import os
            userName = os.environ['USERNAME']
            userDict = {'bgil': 286, 'daniel': 61, 'david': 58, 'dnicolas': 70, 'dperea': 152, 'hector': 62,
                        'jaime': 53, 'jordi': 54, 'jalvarez': 72, 'jgomez': 151, 'lgarcia': 118, 'lucia': 63,
                        'mduque': 187, 'mmartinez': 319, 'pedro': 51, 'pibanez': 153,  'freelance': 385, 'fernando': 67}
            sg_user = userDict.get(userName)
            return sg_user



        version_data = {
            "sg_path_to_frames": get_path_to_frames(),
            "project": item.context.project,
            "code": publish_name,
            "description": item.description,
            "entity": self._get_version_entity(item),
            "sg_task": item.context.task,
            "user": {'type': 'HumanUser', 'id': get_userID()}
        }

        if "sg_publish_data" in item.properties:
            publish_data = item.properties["sg_publish_data"]
            version_data["published_files"] = [publish_data]

        if settings["Link Local File"].value:
            version_data["sg_path_to_movie"] = path

        # log the version data for debugging
        self.logger.debug(
            "Populated Version data...",
            extra={
                "action_show_more_info": {
                    "label": "Version Data",
                    "tooltip": "Show the complete Version data dictionary",
                    "text": "<pre>%s</pre>" % (pprint.pformat(version_data),),
                }
            },
        )

        # Create the version
        version = publisher.shotgun.create("Version", version_data)
        self.logger.info("Version created!")

        # stash the version info in the item just in case
        item.properties["sg_version_data"] = version

        thumb = item.get_thumbnail_as_path()

        if settings["Upload"].value:
            self.logger.info("Uploading content...")

            # on windows, ensure the path is utf-8 encoded to avoid issues with
            # the shotgun api
            if sgtk.util.is_windows():
                upload_path = six.ensure_text(path)
            else:
                upload_path = path

            self.parent.shotgun.upload(
                "Version", version["id"], upload_path, "sg_uploaded_movie"
            )
        elif thumb:
            # only upload thumb if we are not uploading the content. with
            # uploaded content, the thumb is automatically extracted.
            self.logger.info("Uploading thumbnail...")
            self.parent.shotgun.upload_thumbnail("Version", version["id"], thumb)

        self.logger.info("Upload complete!")
    def publish(self, settings, item):
        """
        Executes the publish logic for the given item and settings.

        :param settings: Dictionary of Settings. The keys are strings, matching
            the keys returned in the settings property. The values are `Setting`
            instances.
        :param item: Item to process
        """

        publisher = self.parent
        path = item.properties["path"]

        # get tk object to do some out of scope calls
        tk = publisher.sgtk

        # allow the publish name to be supplied via the item properties. this is
        # useful for collectors that have access to templates and can determine
        # publish information about the item that doesn't require further, fuzzy
        # logic to be used here (the zero config way)
        publish_name = item.properties.get("publish_name")
        if not publish_name:

            self.logger.debug("Using path info hook to determine publish name.")

            # use the path's filename as the publish name
            path_components = publisher.util.get_file_path_components(path)
            publish_name = path_components["filename"]

        self.logger.debug("Publish name: %s" % (publish_name,))

        self.logger.info("Creating Version...")
        version_data = {
            "project": item.context.project,
            "code": publish_name,
            "description": item.description,
            "entity": self._get_version_entity(item),
            "sg_task": item.context.task,
        }

        # if correlates are defined at all, look to see if any matched and then use them
        if settings.get('Source Correlate'):
            correlate = item.properties.get('correlate')
            if correlate:

                update = correlate.get('rule').get('update')
                if update and update.get('entity').lower() == "version":

                    # if there is a destination field for putting the correlated path
                    version_data[update.get('field')] = correlate.get('path')
                    self.logger.info("Correlate media set in %s.%s: %s" % (update.get('entity'),
                                                                           update.get('field'),
                                                                           correlate.get('path')))

        if all(key in item.properties for key in ('first_frame', 'last_frame')):
            first_frame = item.properties["first_frame"]
            last_frame = item.properties["last_frame"]
            version_data["sg_first_frame"] = first_frame
            version_data["sg_last_frame"] = last_frame
            version_data["frame_count"] = int(last_frame - first_frame + 1)
            version_data["frame_range"] = "{}-{}".format(first_frame, last_frame)

        if "sg_publish_data" in item.properties:
            publish_data = item.properties["sg_publish_data"]
            version_data["published_files"] = [publish_data]

            # make local media link dependent on publish file path
            if settings["Link Local File"].value:
                version_data["sg_path_to_movie"] = publish_data.get('path').get('local_path_linux')

        # log the version data for debugging
        self.logger.debug(
            "Populated Version data...",
            extra={
                "action_show_more_info": {
                    "label": "Version Data",
                    "tooltip": "Show the complete Version data dictionary",
                    "text": "<pre>%s</pre>" % (pprint.pformat(version_data),),
                }
            },
        )

        # Create the version
        version = publisher.shotgun.create("Version", version_data)
        self.logger.info("Version created!")

        # stash the version info in the item just in case
        item.properties["sg_version_data"] = version

        thumb = item.get_thumbnail_as_path()

        if settings["Upload"].value:
            self.logger.info("Uploading content...")

            # on windows, ensure the path is utf-8 encoded to avoid issues with
            # the shotgun api
            if sgtk.util.is_windows():
                upload_path = six.ensure_text(path)
            else:
                upload_path = path

            self.parent.shotgun.upload(
                "Version", version["id"], upload_path, "sg_uploaded_movie"
            )
        elif thumb:
            # only upload thumb if we are not uploading the content. with
            # uploaded content, the thumb is automatically extracted.
            self.logger.info("Uploading thumbnail...")
            self.parent.shotgun.upload_thumbnail("Version", version["id"], thumb)

        self.logger.info("Upload complete!")