Exemplo n.º 1
0
    def __get_pipeline_configuration_local_path(self, project_id):
        """
        Get the path to the local configuration (the one which stands in the Sgtk cache folder) in order to be able
        to build a :class`sgtk.Sgtk` instance from this path

        :param project_id: Id of the project we want to retrieve the config for
        :returns: The local path to the config if we could determine which config to use, None otherwise.
        """

        plugin_id = "basic.desktop"

        # first, start the toolkit manager to get all the pipeline configurations related to the distant project
        # here, we are going to use the default plugin id "basic.*" to find the pipeline configurations
        mgr = sgtk.bootstrap.ToolkitManager()
        mgr.plugin_id = sgtk.commands.constants.DEFAULT_PLUGIN_ID
        pipeline_configurations = mgr.get_pipeline_configurations({
            "type":
            "Project",
            "id":
            project_id
        })

        if not pipeline_configurations:
            self.logger.warning(
                "Couldn't retrieve any pipeline configuration linked to project {}"
                .format(project_id))
            return

        if len(pipeline_configurations) == 1:
            pipeline_config = pipeline_configurations[0]

        else:

            # try to determine which configuration we want to use:
            # 1- if one and only one pipeline configuration is restricted to this project, use it
            # 2- if one pipeline configuration is named Primary and linked to this project, use it
            # 3- reject all the other cases

            pipeline_config = self.__get_project_pipeline_configuration(
                pipeline_configurations, project_id)

            if not pipeline_config:
                pipeline_config = self.__get_primary_pipeline_configuration(
                    pipeline_configurations, project_id)

        if not pipeline_config:
            self.logger.warning(
                "Couldn't get the pipeline configuration linked to project {}: too many configurations"
                .format(project_id))
            return None

        config_local_path = LocalFileStorageManager.get_configuration_root(
            self.sgtk.shotgun_url,
            project_id,
            plugin_id,
            pipeline_config["id"],
            LocalFileStorageManager.CACHE,
        )

        return os.path.join(config_local_path, "cfg")
Exemplo n.º 2
0
    def launch_desktop_server(self, host, user_id, parent=None):
        """
        Initializes the desktop server.

        The server actually supports two protocols, named v1 and v2. v1 can be used to process requests from any
        users from any sites, while v2 can only be used to process requests from the currently authenticated
        user.

        :param str host: Host for which we desire to answer requests.
        :param int user_id: Id of the user for which we desire to answer requests.
        :param parent: Parent widget for any pop-ups to show during initialization.
        :type parent: :class:`PySide.QtGui.QWidget`
        """
        # Twisted only runs on 64-bits.
        # No not even attempt to import the framework, as it will cause 64-bits DLLs to be loaded.
        if not self.__is_64bit_python():
            self.logger.warning(
                "The browser integration is only available with 64-bit versions of Python."
            )
            self._integration_enabled = False
            return

        self._tk_framework_desktopserver = self.import_module(
            "tk_framework_desktopserver")

        # Read the browser integration settings from disk. By passing in location=None, the Toolkit API will be
        # used to locate the settings instead of looking at a specific file.
        self._settings = self._tk_framework_desktopserver.Settings(
            location=None,
            default_certificate_folder=os.path.join(
                LocalFileStorageManager.get_global_root(
                    LocalFileStorageManager.CACHE,
                    LocalFileStorageManager.CORE_V18), "desktop", "config",
                "certificates"))
        self._settings.dump(self.logger)

        # Did the user disable it?
        if not self._settings.integration_enabled:
            self.logger.info(
                "Browser integration has been disabled in the Toolkit settings."
            )
            self._integration_enabled = False
        else:
            self._integration_enabled = True

        if not self._integration_enabled:
            return

        try:
            if self._site_supports_shotgunlocalhost():
                self.__retrieve_certificates_from_shotgun()
                keys_path = self._get_shotgunlocalhost_keys_folder()
                encrypt = True
            else:
                self.__ensure_certificate_ready(regenerate_certs=False,
                                                parent=parent)
                keys_path = self._settings.certificate_folder
                encrypt = False

            self._server = self._tk_framework_desktopserver.Server(
                keys_path=keys_path,
                encrypt=encrypt,
                host=host,
                user_id=user_id,
                port=self._settings.port)

            self._server.start()
        except Exception:
            self.logger.exception("Could not start the browser integration:")
Exemplo n.º 3
0
    def get_path_cache_path(self, project_id, plugin_id,
                            pipeline_configuration_id):
        """
        Establish a location for the path cache database file.

        This hook method was introduced in Toolkit v0.18 and replaces path_cache.
        If you already have implemented path_cache, this will be detected and called instead,
        however we strongly recommend that you tweak your hook.

        Overriding this method in a hook allows a user to change the location on disk where
        the path cache file is located. The path cache file holds a temporary cache representation
        of the FilesystemLocation entities stored in Shotgun for a project. Typically, this cache
        is stored on a local machine, separate for each user.  

        Note! In the case of the site configuration, project id will be set to None.
        In the case of an unmanaged pipeline configuration, pipeline config
        id will be set to None.

        :param project_id: The shotgun id of the project to store caches for
        :param plugin_id: Unique string to identify the scope for a particular plugin
                          or integration. For more information,
                          see :meth:`~sgtk.bootstrap.ToolkitManager.plugin_id`. For
                          non-plugin based toolkit projects, this value is None.
        :param pipeline_configuration_id: The shotgun pipeline config id to store caches for
        :returns: The path to a path cache file. This file should exist when this method returns.
        """
        # backwards compatibility with custom hooks created before 0.18
        if hasattr(self, "path_cache") and callable(getattr(
                self, "path_cache")):
            # there is a custom version of the legacy hook path_cache
            log.warning("Detected old core cache hook implementation. "
                        "It is strongly recommended that this is upgraded.")

            # call legacy hook to make sure we call the custom
            # implementation that is provided by the user.
            # this implementation expects project id 0 for
            # the site config, so ensure that's the case too
            if project_id is None:
                project_id = 0

            return self.path_cache(project_id, pipeline_configuration_id)

        cache_filename = "path_cache.db"

        tk = self.parent

        cache_root = LocalFileStorageManager.get_configuration_root(
            tk.shotgun_url, project_id, plugin_id, pipeline_configuration_id,
            LocalFileStorageManager.CACHE)

        target_path = os.path.join(cache_root, cache_filename)

        if os.path.exists(target_path):
            # new style path cache file exists, return it
            return target_path

        # The target path does not exist. This could be because it just hasn't
        # been created yet, or it could be because of a core upgrade where the
        # cache root directory structure has changed (such is the case with
        # v0.17.x -> v0.18.x). To account for this scenario, see if the target
        # exists in an old location first, and if so, return that path instead.
        legacy_cache_root = LocalFileStorageManager.get_configuration_root(
            tk.shotgun_url,
            project_id,
            plugin_id,
            pipeline_configuration_id,
            LocalFileStorageManager.CACHE,
            generation=LocalFileStorageManager.CORE_V17)

        legacy_target_path = os.path.join(legacy_cache_root, cache_filename)

        if os.path.exists(legacy_target_path):
            # legacy path cache file exists, return it
            return legacy_target_path

        # neither new style or legacy path cache exists. use the new style
        filesystem.ensure_folder_exists(cache_root)
        filesystem.touch_file(target_path)

        return target_path
Exemplo n.º 4
0
    def get_bundle_data_cache_path(self, project_id, plugin_id,
                                   pipeline_configuration_id, bundle):
        """
        Establish a cache folder for an app, engine or framework.

        This hook method was introduced in Toolkit v0.18 and replaces bundle_cache.
        If you already have implemented bundle_cache, this will be detected and called instead,
        however we strongly recommend that you tweak your hook.
        
        Apps, Engines or Frameworks commonly caches data on disk. This can be 
        small files, shotgun queries, thumbnails etc. This method implements the 
        logic which defines this location on disk. The cache should be organized in 
        a way so that all instances of the app can re-use the same data. (Apps 
        which needs to cache things per-instance can implement this using a sub
        folder inside the bundle cache location).

        It is possible to omit some components of the path by explicitly passing
        a `None` value for them, only the bundle name is required. For example,
        with `project_id=None`, a site level cache path will be returned.
        Ommitting the `project_id` can be used to cache data for the site
        configuration, or to share data accross all projects belonging to a
        common site.

        :param project_id: The shotgun id of the project to store caches for, or None.
        :param plugin_id: Unique string to identify the scope for a particular plugin
                          or integration, or None. For more information,
                          see :meth:`~sgtk.bootstrap.ToolkitManager.plugin_id`. For
                          non-plugin based toolkit projects, this value is None.
        :param pipeline_configuration_id: The shotgun pipeline config id to store caches for, or None.
        :param bundle: The app, engine or framework object which is requesting the cache folder.
        :returns: The path to a folder which should exist on disk.
        """
        # backwards compatibility with custom hooks created before 0.18
        if hasattr(self, "bundle_cache") and callable(
                getattr(self, "bundle_cache")):
            # there is a custom version of the legacy hook path_cache
            log.warning("Detected old core cache hook implementation. "
                        "It is strongly recommended that this is upgraded.")

            # call legacy hook to make sure we call the custom
            # implementation that is provided by the user.
            # this implementation expects project id 0 for
            # the site config, so ensure that's the case too
            if project_id is None:
                project_id = 0

            return self.bundle_cache(project_id, pipeline_configuration_id,
                                     bundle)

        tk = self.parent
        cache_root = LocalFileStorageManager.get_configuration_root(
            tk.shotgun_url, project_id, plugin_id, pipeline_configuration_id,
            LocalFileStorageManager.CACHE)

        # in the interest of trying to minimize path lengths (to avoid
        # the MAX_PATH limit on windows, we apply some shortcuts

        # if the bundle is a framework, we shorten it:
        # tk-framework-shotgunutils --> fw-shotgunutils
        # if the bundle is a multi-app, we shorten it:
        # tk-multi-workfiles2 --> tm-workfiles2
        bundle_name = bundle.name
        bundle_name = bundle_name.replace("tk-framework-", "fw-")
        bundle_name = bundle_name.replace("tk-multi-", "tm-")

        target_path = os.path.join(cache_root, bundle_name)

        if os.path.exists(target_path):
            # new style cache bundle folder exists, return it
            return target_path

        # The target path does not exist. This could be because it just hasn't
        # been created yet, or it could be because of a core upgrade where the
        # cache root directory structure has changed (such is the case with
        # v0.17.x -> v0.18.x). To account for this scenario, see if the target
        # exists in an old location first, and if so, return that path instead.
        legacy_cache_root = LocalFileStorageManager.get_configuration_root(
            tk.shotgun_url,
            project_id,
            plugin_id,
            pipeline_configuration_id,
            LocalFileStorageManager.CACHE,
            generation=LocalFileStorageManager.CORE_V17)
        legacy_target_path = os.path.join(legacy_cache_root, bundle.name)

        if os.path.exists(legacy_target_path):
            # legacy cache bundle folder exists, return it
            return legacy_target_path

        # neither new style or legacy path cache exists. use the new style
        filesystem.ensure_folder_exists(target_path)

        return target_path
Exemplo n.º 5
0
    def get_path_cache_path(self, project_id, plugin_id, pipeline_configuration_id):
        """
        Establish a location for the path cache database file.

        This hook method was introduced in Toolkit v0.18 and replaces the previous
        ``path_cache`` method. If you already have implemented ``path_cache``,
        this will be detected and called instead, however we strongly recommend
        that you tweak your hook.

        Overriding this method in a hook allows a user to change the location on disk where
        the path cache file is located. The path cache file holds a temporary cache representation
        of the ``FilesystemLocation`` entities stored in Shotgun for a project.

        The default implementation will create a folder inside the user's home folder or
        under ``SHOTGUN_HOME``.

        :param int project_id: The Shotgun id of the project to store caches for. None if
                               the configuration is a site configuration.
        :param str plugin_id: Unique string to identify the scope for a particular plugin
                              or integration. For more information,
                              see :meth:`~sgtk.bootstrap.ToolkitManager.plugin_id`. For
                              non-plugin based toolkit projects, this value is None.
        :param int pipeline_configuration_id: The Shotgun pipeline configuration id to store caches
                                              for. If the pipeline configuration is unmanaged, it
                                              will be ``None``
        :returns: The path to a path cache file. This file should exist when this method returns.
        :rtype: str
        """
        # backwards compatibility with custom hooks created before 0.18
        if hasattr(self, "path_cache") and callable(getattr(self, "path_cache")):
            # there is a custom version of the legacy hook path_cache
            log.warning(
                "Detected old core cache hook implementation. "
                "It is strongly recommended that this is upgraded."
            )

            # call legacy hook to make sure we call the custom
            # implementation that is provided by the user.
            # this implementation expects project id 0 for
            # the site config, so ensure that's the case too
            if project_id is None:
                project_id = 0

            return self.path_cache(project_id, pipeline_configuration_id)

        cache_filename = "path_cache.db"

        tk = self.parent

        cache_root = LocalFileStorageManager.get_configuration_root(
            tk.shotgun_url,
            project_id,
            plugin_id,
            pipeline_configuration_id,
            LocalFileStorageManager.CACHE
        )

        target_path = os.path.join(cache_root, cache_filename)

        if os.path.exists(target_path):
            # new style path cache file exists, return it
            return target_path

        # The target path does not exist. This could be because it just hasn't
        # been created yet, or it could be because of a core upgrade where the
        # cache root directory structure has changed (such is the case with
        # v0.17.x -> v0.18.x). To account for this scenario, see if the target
        # exists in an old location first, and if so, return that path instead.
        legacy_cache_root = LocalFileStorageManager.get_configuration_root(
            tk.shotgun_url,
            project_id,
            plugin_id,
            pipeline_configuration_id,
            LocalFileStorageManager.CACHE,
            generation=LocalFileStorageManager.CORE_V17
        )

        legacy_target_path = os.path.join(legacy_cache_root, cache_filename)

        if os.path.exists(legacy_target_path):
            # legacy path cache file exists, return it
            return legacy_target_path

        # neither new style or legacy path cache exists. use the new style
        filesystem.ensure_folder_exists(cache_root)
        filesystem.touch_file(target_path)

        return target_path
Exemplo n.º 6
0
    def get_bundle_data_cache_path(self, project_id, plugin_id, pipeline_configuration_id, bundle):
        """
        Establish a cache folder for an app, engine or framework.

        This hook method was introduced in Toolkit v0.18 and replaces the previous ``bundle_cache``
        method. If you already have implemented ``bundle_cache``, this will be detected and called
        instead, however we strongly recommend that you tweak your hook.

        Apps, Engines or Frameworks commonly cache data on disk. This can be
        small files, Shotgun queries, thumbnails, etc. This method implements the
        logic which defines this location on disk. The cache should be organized in
        a way so that all instances of the app can re-use the same data. Bundles
        which need to cache things per-instance can implement this using a sub
        folder inside the bundle cache location.

        It is possible to omit some components of the path by explicitly passing
        a ``None`` value for them. Only the bundle name is required. For example,
        with ``project_id=None``, a site level cache path will be returned.
        Omitting the ``project_id`` can be used to cache data for the site
        configuration, or to share data accross all projects belonging to a
        common site.

        The default implementation will create a folder inside the user's home folder or
        under ``SHOTGUN_HOME``.

        :param int project_id: The Shotgun id of the project to store caches for, or None.
        :param str plugin_id: Unique string to identify the scope for a particular plugin
                              or integration, or None. For more information,
                              see :meth:`~sgtk.bootstrap.ToolkitManager.plugin_id`. For
                              non-plugin based toolkit projects, this value is None.
        :param int pipeline_configuration_id: The Shotgun pipeline config id to store caches for
                                              or ``None`` if the pipeline configuration is unmanaged.
        :param bundle: The app, engine or framework object which is requesting the cache folder.
        :type bundle: :class:`~sgtk.platform.Engine`, :class:`~sgtk.platform.Framework` or
                      :class:`~sgtk.platform.Application`
        :returns: The path to a folder which should exist on disk.
        :rtype: str
        """
        # backwards compatibility with custom hooks created before 0.18
        if hasattr(self, "bundle_cache") and callable(getattr(self, "bundle_cache")):
            # there is a custom version of the legacy hook path_cache
            log.warning(
                "Detected old core cache hook implementation. "
                "It is strongly recommended that this is upgraded."
            )

            # call legacy hook to make sure we call the custom
            # implementation that is provided by the user.
            # this implementation expects project id 0 for
            # the site config, so ensure that's the case too
            if project_id is None:
                project_id = 0

            return self.bundle_cache(project_id, pipeline_configuration_id, bundle)

        tk = self.parent
        cache_root = LocalFileStorageManager.get_configuration_root(
            tk.shotgun_url,
            project_id,
            plugin_id,
            pipeline_configuration_id,
            LocalFileStorageManager.CACHE
        )

        # in the interest of trying to minimize path lengths (to avoid
        # the MAX_PATH limit on windows, we apply some shortcuts

        # if the bundle is a framework, we shorten it:
        # tk-framework-shotgunutils --> fw-shotgunutils
        # if the bundle is a multi-app, we shorten it:
        # tk-multi-workfiles2 --> tm-workfiles2
        bundle_name = bundle.name
        bundle_name = bundle_name.replace("tk-framework-", "fw-")
        bundle_name = bundle_name.replace("tk-multi-", "tm-")

        target_path = os.path.join(cache_root, bundle_name)

        if os.path.exists(target_path):
            # new style cache bundle folder exists, return it
            return target_path

        # The target path does not exist. This could be because it just hasn't
        # been created yet, or it could be because of a core upgrade where the
        # cache root directory structure has changed (such is the case with
        # v0.17.x -> v0.18.x). To account for this scenario, see if the target
        # exists in an old location first, and if so, return that path instead.
        legacy_cache_root = LocalFileStorageManager.get_configuration_root(
            tk.shotgun_url,
            project_id,
            plugin_id,
            pipeline_configuration_id,
            LocalFileStorageManager.CACHE,
            generation=LocalFileStorageManager.CORE_V17
        )
        legacy_target_path = os.path.join(legacy_cache_root, bundle.name)

        if os.path.exists(legacy_target_path):
            # legacy cache bundle folder exists, return it
            return legacy_target_path

        # neither new style or legacy path cache exists. use the new style
        filesystem.ensure_folder_exists(target_path)

        return target_path
    def launch_desktop_server(self, host, user_id, parent=None):
        """
        Initializes the desktop server.

        The server actually supports two protocols, named v1 and v2. v1 can be used to process requests from any
        users from any sites, while v2 can only be used to process requests from the currently authenticated
        user.

        :param str host: Host for which we desire to answer requests.
        :param int user_id: Id of the user for which we desire to answer requests.
        :param parent: Parent widget for any pop-ups to show during initialization.
        :type parent: :class:`PySide.QtGui.QWidget`
        """
        # Twisted only runs on 64-bits.
        # No not even attempt to import the framework, as it will cause 64-bits DLLs to be loaded.
        if not self.__is_64bit_python():
            self.logger.warning("The browser integration is only available with 64-bit versions of Python.")
            self._integration_enabled = False
            return

        self._tk_framework_desktopserver = self.import_module("tk_framework_desktopserver")

        # Read the browser integration settings from disk. By passing in location=None, the Toolkit API will be
        # used to locate the settings instead of looking at a specific file.
        self._settings = self._tk_framework_desktopserver.Settings(
            default_certificate_folder=os.path.join(
                LocalFileStorageManager.get_global_root(
                    LocalFileStorageManager.CACHE, LocalFileStorageManager.CORE_V18
                ),
                "desktop",
                "config",
                "certificates"
            )
        )
        self._settings.dump(self.logger)

        # Did the user disable it?
        if not self._settings.integration_enabled:
            self.logger.info("Browser integration has been disabled in the Toolkit settings.")
            self._integration_enabled = False
        else:
            self._integration_enabled = True

        if not self._integration_enabled:
            return

        try:
            if self._site_supports_shotgunlocalhost():
                self.__retrieve_certificates_from_shotgun()
                keys_path = self._get_shotgunlocalhost_keys_folder()
                encrypt = True
            else:
                self.__ensure_certificate_ready(regenerate_certs=False, parent=parent)
                keys_path = self._settings.certificate_folder
                encrypt = False

            self._server = self._tk_framework_desktopserver.Server(
                keys_path=keys_path,
                encrypt=encrypt,
                host=host,
                user_id=user_id,
                host_aliases=self._get_host_aliases(host),
                port=self._settings.port
            )

            self._server.start()
        except Exception:
            self.logger.exception("Could not start the browser integration:")