Exemple #1
0
def bootstrap_plugin():
    """
    Bootstrap this plugin.
    """
    # measure the time it takes to start up
    time_before = time.time()

    # Initialize logging to disk
    sgtk.LogManager().initialize_base_file_handler(ENGINE_NAME)

    # Log to stderr if TK_DEBUG is enabled.
    if sgtk.LogManager().global_debug:
        sgtk.LogManager().initialize_custom_handler()

    logger = sgtk.LogManager.get_logger("bootstrap")
    logger.debug("Bootstrapping %s..." % ENGINE_NAME)

    # Figure out our location
    plugin_root_dir = os.path.abspath(os.path.dirname(__file__))
    plugin_python_path = os.path.join(plugin_root_dir, "python")

    # As a baked plugin we do have manifest.py we can use to bootstrap.

    # Instead of adding an extra path in the PYTHONPATH to be able to load the
    # manifest module and clean up the PYTHONPATH up after the import, we use
    # `imp` utilities to load the manifest module.
    try:
        mfile, pathname, description = imp.find_module(
            "sgtk_plugin_test_plugin", [plugin_python_path])
    except ImportError:
        logger.error(
            "Unable to find 'sgtk_plugin_test_plugin', was the plugin baked?")
        raise

    try:
        sgtk_plugin_test_plugin = imp.load_module("sgtk_plugin_test_plugin",
                                                  mfile, pathname, description)
    finally:
        if mfile:
            mfile.close()

    # This module is built with the plugin and contains the manifest.py.
    manifest = sgtk_plugin_test_plugin.manifest

    # start up toolkit via the manager - we should be authenticated already.
    manager = sgtk.bootstrap.ToolkitManager()
    manifest.initialize_manager(manager, plugin_root_dir)

    # This plugin is fully baked and cannot be overridden
    # via a Shotgun Pipeline Configuration.
    # Note: Individual apps can however be overridden since
    #       the execute in external processes.
    manager.do_shotgun_config_lookup = False

    # start up in site mode.
    engine = manager.bootstrap_engine(ENGINE_NAME, entity=None)
    logger.debug("%s started." % engine.name)

    time_spent = time.time() - time_before
    engine.log_info("Toolkit integration launched in %ss" % time_spent)
 def _enable_file_based_logging(self):
     """
     Enables file based logging to the tk-desktop log file.
     """
     # We're about to disconnect from the site engine, restore our own logging system. It is possible that it has
     # already been re-enabled already however. This happens when the desktop site engine disconnects from us and
     # triggers _signal_disconnect, which re-enables logging while we are still running some UIs, in which case
     # the engine will be destroyed only when the last dialog will be closed. At that point, we don't need to
     # initialize the base file handler. Ensuring that it is not enabled means there won't be spurious log
     # messages about switching handlers in the log files.
     if not sgtk.LogManager().base_file_handler:
         logger.debug("Project-level tk-desktop engine will now switch back to file based logging.")
         sgtk.LogManager().initialize_base_file_handler("tk-desktop")
Exemple #3
0
def __backup_global_debug_flag():
    """
    Backups the global debug flag.
    """
    global global_debug_flag_at_startup
    import sgtk
    global_debug_flag_at_startup = sgtk.LogManager().global_debug
Exemple #4
0
def _handle_bootstrap_failed(phase, exception):
    """
    Callback function that handles cleanup after failed completion of the bootstrap.

    This function is executed in the main thread by the main event loop.

    :param phase: Bootstrap phase that raised the exception,
                  ``ToolkitManager.TOOLKIT_BOOTSTRAP_PHASE`` or ``ToolkitManager.ENGINE_STARTUP_PHASE``.
    :param exception: Python exception raised while bootstrapping.
    """

    # Needed global to re-import the toolkit core.
    global sgtk

    if phase is None or phase == sgtk.bootstrap.ToolkitManager.ENGINE_STARTUP_PHASE:
        # Re-import the toolkit core to ensure usage of a swapped in version.
        import sgtk

    # Hide the progress bar.
    _hide_progress_bar()

    # Report the encountered exception.
    # the message displayed last will be the one visible in the script editor,
    # so make sure this is the error message summary.
    OpenMaya.MGlobal.displayError("An exception was raised during Shotgun startup: %s" % exception)
    OpenMaya.MGlobal.displayError("For details, see log files in %s" % sgtk.LogManager().log_folder)
    OpenMaya.MGlobal.displayError("Error loading Shotgun integration.")

    # Clear the user's credentials to log him/her out.
    sgtk.authentication.ShotgunAuthenticator().clear_default_user()

    # Re-display the login menu.
    _create_login_menu()
Exemple #5
0
def start_toolkit():
    """
    Import Toolkit and start up a tk-harmony engine based on
    environment variables.
    """

    # Verify sgtk can be loaded.
    try:
        import sgtk
    except Exception as e:
        msg = "Shotgun: Could not import sgtk! Disabling for now: %s" % e
        display_error(msg)
        return

    # start up toolkit logging to file
    sgtk.LogManager().initialize_base_file_handler("tk-harmony")

    # Rely on the classic boostrapping method
    start_toolkit_classic()

    # Check if a file was specified to open and open it.
    file_to_open = os.environ.get("SGTK_FILE_TO_OPEN")
    if file_to_open:
        msg = "Shotgun: Opening '%s'..." % file_to_open
        display_info(msg)
        # TODO load a project if specified
        # .App.loadProject(file_to_open)

    # Clean up temp env variables.
    del_vars = ["SGTK_ENGINE", "SGTK_CONTEXT", "SGTK_FILE_TO_OPEN"]
    for var in del_vars:
        if var in os.environ:
            del os.environ[var]
Exemple #6
0
    def _set_global_debug(self, state):
        """
        Sets the global debug to the given state.

        :param bool state: The debug state to set.
        """
        sgtk.LogManager().global_debug = state
Exemple #7
0
def launch_engine():

    # Imported locally to avoid use after bootstrap.
    import sgtk

    # Installs a StreamHandler so we see the server output in the console.
    sgtk.LogManager().initialize_base_file_handler("tk-multi-publish2.test")

    # Set the repo root environment variable that is used by the config.
    repo_root = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")
    repo_root = os.path.normpath(repo_root)
    os.environ["REPO_ROOT"] = repo_root
    os.environ["SHOTGUN_EXTERNAL_REPOS_ROOT"] = os.path.dirname(repo_root)

    # Authenticate
    user = sgtk.authentication.ShotgunAuthenticator().get_user()
    sg = user.create_sg_connection()

    project = sg.find_one("Project", [["tank_name", "is_not", None]])
    if project is None:
        raise RuntimeError(
            "You need at least one project with the Project.tank_name field set."
        )

    # Bootstrap
    manager = sgtk.bootstrap.ToolkitManager(user)
    manager.plugin_id = "basic.shell"
    manager.base_configuration = (
        "sgtk:descriptor:path?path=$REPO_ROOT/tests/fixtures/config")
    manager.do_shotgun_config_lookup = False
    manager.progress_callback = progress_callback

    return manager.bootstrap_engine("tk-shell", project)
def launch_engine():

    # Imported locally to avoid use after bootstrap.
    import sgtk

    # Installs a StreamHandler so we see the server output in the console.
    sgtk.LogManager().initialize_base_file_handler("tk-multi-publish2.test")

    # Authenticate
    user = sgtk.authentication.ShotgunAuthenticator().get_user()
    sg = user.create_sg_connection()

    project = sg.find_one("Project", [["tank_name", "is_not", None]])
    if project is None:
        raise RuntimeError(
            "You need at least one project with the Project.tank_name field set."
        )

    # Bootstrap
    manager = sgtk.bootstrap.ToolkitManager(user)
    manager.plugin_id = "basic.shell"
    manager.base_configuration = (
        "sgtk:descriptor:path?path=$REPO_ROOT/tests/fixtures/config")
    manager.do_shotgun_config_lookup = False
    manager.progress_callback = progress_callback

    return manager.bootstrap_engine("tk-shell", project)
Exemple #9
0
    def _connect_to_server(self):
        """
        Connects to the other process's server and starts our own.
        """
        # pull the data on how to connect to the GUI proxy from the tk instance
        bootstrap_data = self._engine.sgtk._desktop_data
        proxy_pipe = bootstrap_data["proxy_pipe"]
        proxy_auth = bootstrap_data["proxy_auth"]

        # We always prefer the HTTP pipe, as it works under every Python version.
        self._project_comm.connect_to_server(proxy_pipe, proxy_auth,
                                             self._signal_disconnect)
        # Stop logging to disk
        sgtk.LogManager().uninitialize_base_file_handler()
        logger.debug(
            "Project-level tk-desktop engine has now switched back to proxy based logging."
        )

        self._project_comm.register_function(self._trigger_callback,
                                             "trigger_callback")
        self._project_comm.register_function(self._test_project_locations,
                                             "test_project_locations")
        self._project_comm.register_function(self._open_project_locations,
                                             "open_project_locations")
        self._project_comm.register_function(self._get_setting, "get_setting")
        self._project_comm.register_function(self._set_global_debug,
                                             "set_global_debug")
Exemple #10
0
def bootstrap_toolkit(root_path):
    """
    Entry point for toolkit bootstrap in 3dsmax.
    Called by the bootstrap.ms max script.

    :param str root_path: Path to the root folder of the plugin
    """

    # --- Import Core ---
    #
    # - If we are running the plugin built as a stand-alone unit,
    #   try to retrieve the path to sgtk core and add that to the pythonpath.
    #   When the plugin has been built, there is a sgtk_plugin_basic_3dsmax
    #   module which we can use to retrieve the location of core and add it
    #   to the pythonpath.
    # - If we are running toolkit as part of a larger zero config workflow
    #   and not from a standalone workflow, we are running the plugin code
    #   directly from the engine folder without a bundle cache and with this
    #   configuration, core already exists in the pythonpath.

    # Display temporary message in prompt line for maximum 5 secs.
    rt.displayTempPrompt("Loading Shotgun integration...", 5000)

    # Remember path, to handle logout/login
    PluginProperties.plugin_root_path = root_path

    try:
        from sgtk_plugin_basic_3dsmax import manifest

        PluginProperties.running_as_standalone_plugin = True
    except ImportError:
        PluginProperties.running_as_standalone_plugin = False

    if PluginProperties.running_as_standalone_plugin:
        # Retrieve the Shotgun toolkit core included with the plug-in and
        # prepend its python package path to the python module search path.
        tkcore_python_path = manifest.get_sgtk_pythonpath(
            PluginProperties.plugin_root_path)
        sys.path.insert(0, tkcore_python_path)
        import sgtk

    else:
        # Running as part of the the launch process and as part of zero
        # config. The launch logic that started 3dsmax has already
        # added sgtk to the pythonpath.
        import sgtk

    # start logging to log file
    sgtk.LogManager().initialize_base_file_handler("tk-3dsmax")

    # get a logger for the plugin
    sgtk_logger = sgtk.LogManager.get_logger(PLUGIN_PACKAGE_NAME)
    sgtk_logger.debug("Booting up toolkit plugin.")

    if sgtk.authentication.ShotgunAuthenticator().get_default_user():
        # When the user is already authenticated, automatically log him/her in.
        _login_user()
    else:
        # When the user is not yet authenticated, display a login menu.
        _create_login_menu()
def bootstrap_toolkit(configuration_id, context, engine_instance_name):
    """
    Syncs the path cache and starts Toolkit.

    The method expects SHOTGUN_HOST, SHOTGUN_SCRIPT_NAME and
    SHOTGUN_SCRIPT_KEY to be set to authenticate with Shotgun. If not,
    it will fail.
    """
    # When writing bootstrap scripts, always make sure to locally import
    # Toolkit. This will ensure you are using the right copy of the
    # module after bootstrapping, which will swap the cached copy of
    # Toolkit in sys.module, but can't update the references you have
    # to it.
    import sgtk

    # Set up logging.
    sgtk.LogManager().initialize_base_file_handler("tk-batch-rendering")

    # Never hard code credentials in your scripts.
    user = sgtk.authentication.ShotgunAuthenticator().create_script_user(
        os.environ["SHOTGUN_SCRIPT_NAME"], os.environ["SHOTGUN_SCRIPT_KEY"],
        os.environ["SHOTGUN_HOST"])

    # Set the right pipeline configuration.
    tk_manager = sgtk.bootstrap.ToolkitManager(user)
    tk_manager.plugin_id = "basic.batch"
    tk_manager.pipeline_configuration = configuration_id

    # Sync the path cache before the engine starts. The engine validates the templates
    # when it starts so path cache has to be already synced.
    tk_manager.pre_engine_start_callback = lambda ctx: ctx.sgtk.synchronize_filesystem_structure(
    )

    # Start the engine, we're done!
    return tk_manager.bootstrap_engine(engine_instance_name, context)
Exemple #12
0
 def _emit_log_message(self, handler, record):
     """
     Called by the engine whenever a new log message is available.
     All log messages from the toolkit logging namespace will be passed to this method.
     .. note:: To implement logging in your engine implementation, subclass
               this method and display the record in a suitable way - typically
               this means sending it to a built-in DCC console. In addition to this,
               ensure that your engine implementation *does not* subclass
               the (old) :meth:`Engine.log_debug`, :meth:`Engine.log_info` family
               of logging methods.
               For a consistent output, use the formatter that is associated with
               the log handler that is passed in. A basic implementation of
               this method could look like this::
                   # call out to handler to format message in a standard way
                   msg_str = handler.format(record)
                   # display message
                   print msg_str
     .. warning:: This method may be executing called from worker threads. In DCC
                  environments, where it is important that the console/logging output
                  always happens in the main thread, it is recommended that you
                  use the :meth:`async_execute_in_main_thread` to ensure that your
                  logging code is writing to the DCC console in the main thread.
     :param handler: Log handler that this message was dispatched from
     :type handler: :class:`~python.logging.LogHandler`
     :param record: Std python logging record
     :type record: :class:`~python.logging.LogRecord`
     """
     log_debug = record.levelno < logging.INFO and sgtk.LogManager(
     ).global_debug
     log_info_above = record.levelno >= logging.INFO
     if log_debug or log_info_above:
         msg = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f")[:-3]
         print(msg, handler.format(record))
def toolkit_classic_bootstrap():
    """
    Business logic for bootstrapping toolkit as a traditional setup.
    """
    import sgtk

    logger = sgtk.LogManager.get_logger(__name__)

    # ---- setup logging
    log_handler = log.get_sgtk_logger(sgtk)
    logger.info("Launching Toolkit in classic mode.")
    logger.debug("TANK_CONTEXT and TANK_ENGINE variables found.")

    # Deserialize the Context object and use that when starting
    # the engine.
    context = sgtk.context.deserialize(os.environ["TANK_CONTEXT"])
    engine_name = os.environ["TANK_ENGINE"]

    logger.info("Starting %s using context %s..." % (engine_name, context))
    sgtk.platform.start_engine(engine_name, context.tank, context)

    # ---- tear down logging
    sgtk.LogManager().root_logger.removeHandler(log_handler)
    logger.debug("Removed bootstrap log handler from root logger...")
    logger.info("Toolkit Bootstrapped!")
    def __init__(self, parent=None):
        super(Console, self).__init__(parent)

        self.setWindowTitle('Shotgun Desktop Console')
        self.setWindowIcon(
            QtGui.QIcon(":/tk-desktop/default_systray_icon.png"))

        self.__logs = QtGui.QPlainTextEdit()
        layout = QtGui.QHBoxLayout()
        layout.addWidget(self.__logs)
        self.setLayout(layout)

        # configure the text widget
        self.__logs.setReadOnly(True)
        self.__logs.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.__logs.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
        self.__logs.customContextMenuRequested.connect(
            self.on_logs_context_menu_request)
        self.__logs.setStyleSheet("QPlainTextEdit:focus { border: none; }")

        # load up previous size
        self._settings_manager = settings.UserSettings(
            sgtk.platform.current_bundle())
        pos = self._settings_manager.retrieve(
            "console.pos", self.pos(), self._settings_manager.SCOPE_GLOBAL)
        size = self._settings_manager.retrieve(
            "console.size", QtCore.QSize(800, 400),
            self._settings_manager.SCOPE_GLOBAL)

        self.move(pos)
        self.resize(size)

        self.__console_handler = ConsoleLogHandler(self)
        sgtk.LogManager().initialize_custom_handler(self.__console_handler)
 def _cleanup_temp_dir(cls):
     """
     Called to cleanup the test folder.
     """
     # Close the file logger so that the file is not in use on Windows.
     sgtk.LogManager().uninitialize_base_file_handler()
     safe_delete_folder(cls.temp_dir)
Exemple #16
0
def __restore_global_debug_flag():
    """
    Restores the global debug flag
    """
    global global_debug_flag_at_startup
    import sgtk
    # If there is no LogManager for the new core, there's no need to restore any flag.
    if hasattr(sgtk, "LogManager"):
        sgtk.LogManager().global_debug = global_debug_flag_at_startup
Exemple #17
0
def __launch_sgtk(base_config, plugin_id, bundle_cache):
    """
    Launches Toolkit and the engine.

    :param str base_config: Basic configuration to use for this plugin instance.
    :param str plugin_id: Plugin id of this plugin instance.
    :param str bundle_cache: Alternate bundle cache location. Can be ``None``.
    """

    # ---- now we have everything needed to bootstrap. finish initializing the
    #      manager and logger, authenticate, then bootstrap the engine.

    import sgtk

    # start logging to log file
    sgtk.LogManager().initialize_base_file_handler("tk-nuke")

    # get a logger for the plugin
    sgtk_logger = sgtk.LogManager.get_logger("plugin")
    sgtk_logger.debug("Booting up toolkit plugin.")

    sgtk_logger.debug("Executable: %s", sys.executable)
    sgtk_logger.debug("Studio environment set?: %s", nuke.env.get("studio"))
    sgtk_logger.debug("Hiero environment set?: %s", nuke.env.get("hiero"))

    try:
        # When the user is not yet authenticated, pop up the Shotgun login
        # dialog to get the user's credentials, otherwise, get the cached user's
        # credentials.
        user = sgtk.authentication.ShotgunAuthenticator().get_user()
    except sgtk.authentication.AuthenticationCancelled:
        # TODO: show a "Shotgun > Login" menu in nuke
        sgtk_logger.info("Shotgun login was cancelled by the user.")
        return

    # Create a boostrap manager for the logged in user with the plug-in
    # configuration data.
    toolkit_mgr = sgtk.bootstrap.ToolkitManager(user)

    toolkit_mgr.base_configuration = base_config
    toolkit_mgr.plugin_id = plugin_id

    # include the bundle cache as a fallback if supplied
    if bundle_cache:
        toolkit_mgr.bundle_cache_fallback_paths = [bundle_cache]

    # Retrieve the Shotgun entity type and id when they exist in the
    # environment. These are passed down through the app launcher when running
    # in zero config
    entity = toolkit_mgr.get_entity_from_environment()
    sgtk_logger.debug("Will launch the engine with entity: %s", entity)

    bootstrapper = NukeBootstraper(toolkit_mgr, entity, sgtk_logger)
    bootstrapper.bootstrap()
Exemple #18
0
    def start_engine(self):
        """
        Bootstraps the engine and launches it.
        """
        # Import Toolkit, but make sure we're not inheriting the parent process's current
        # pipeline configuration.
        sys.path.insert(0, self._core_python_path)
        import sgtk
        del os.environ["TANK_CURRENT_PC"]

        # Connect to the main desktop process so we can send updates to it.
        # We're not guanranteed if the py or pyc file will be passed back to us
        # from the desktop due to write permissions on the folder.
        rpc_lib = imp.load_source("rpc", self._rpc_lib_path)
        self._proxy = rpc_lib.RPCProxy(self._proxy_data["proxy_pipe"],
                                       self._proxy_data["proxy_auth"])
        try:
            # Set up logging with the rpc.
            self._handler = ProxyLoggingHandler(self._proxy)
            sgtk.LogManager().root_logger.addHandler(self._handler)

            # Get the user we should be running as.
            self._user = sgtk.authentication.deserialize_user(
                os.environ["SHOTGUN_DESKTOP_CURRENT_USER"])

            # Prepare the manager based on everything the bootstrap manager expected of us.
            manager = sgtk.bootstrap.ToolkitManager(self._user)
            manager.restore_settings(self._manager_settings)
            manager.pre_engine_start_callback = self._pre_engine_start_callback
            manager.progress_callback = self._progress_callback

            # We're now ready to start the engine.
            return manager.bootstrap_engine("tk-desktop", self._project)
        except Exception as exc:
            # We have a situation here where, on Windows, we end up with some
            # kind of leaked connection back to the server. This results in
            # the connection attempt from the handle_error function hanging
            # until the parent process is killed. The error is never reported
            # as a result.
            #
            # Instead, we'll handle the exception here and use the RPCProxy
            # connection we already have.
            handle_error(self._raw_data, self._proxy)
            exc.sgtk_exception_handled = True
            raise
        finally:
            # Make sure we're closing our proxy so the error reporting,
            # which also creates a proxy, can create its own. If there's an
            # error, make sure we catch it and ignore it. Then the finally
            # can do its job and propagate the real error if there was one.
            try:
                self._proxy.close()
            except:
                pass
def toolkit_plugin_bootstrap(plugin_root_path):
    """
    Business logic for bootstrapping toolkit as a plugin.

    :param plugin_root_path: Path to the root of the plugin
    """

    # import sgtk
    tk_core_python_path = manifest.get_sgtk_pythonpath(plugin_root_path)
    sys.path.insert(0, tk_core_python_path)
    import sgtk

    logger = sgtk.LogManager.get_logger(__name__)
    logger.debug("Imported sgtk core from '%s'" % tk_core_python_path)

    # ---- setup logging
    log_handler = log.get_sgtk_logger(sgtk)
    logger.debug("Added bootstrap log hander to root logger...")

    # set up the toolkit bootstrap manager

    # todo: For standalone workflows, need to handle authentication here
    #       this includes workflows for logging in and out (see maya plugin).
    #       For now, assume that we are correctly authenticated.
    #       Also, need to check that the SHOTGUN_SITE env var matches
    #       the currently logged in site.

    toolkit_mgr = sgtk.bootstrap.ToolkitManager()
    # run the default init which sets plugin id, base config and bundle cache path
    manifest.initialize_manager(toolkit_mgr, plugin_root_path)

    # set up progress reporting
    toolkit_mgr.progress_callback = _progress_handler
    logger.debug("Toolkit Manager: %s" % toolkit_mgr)

    entity = toolkit_mgr.get_entity_from_environment()
    logger.debug("Will launch the engine with entity: %s" % entity)

    logger.info("Bootstrapping toolkit...")
    engine_to_start = os.getenv("SHOTGUN_ENGINE", None)
    if engine_to_start is None:
        logger.error(
            "No engine to start is specified. Make shure SHOTGUN_ENGINE is set in the bootstrap of your engine."
        )
        return

    toolkit_mgr.bootstrap_engine(engine_to_start, entity=entity)

    # ---- tear down logging
    sgtk.LogManager().root_logger.removeHandler(log_handler)
    logger.debug("Removed bootstrap log handler from root logger...")

    logger.info("Toolkit Bootstrapped!")
Exemple #20
0
 def setup(self):
     """
     Make sure we load shotgun
     """
     try:
         if os.environ.get('SG_PYTHONPATH'):
             paths = os.environ.get('SG_PYTHONPATH').split(os.pathsep)
             for p in paths:
                 sys.path.append(p)
         import sgtk
         sgtk.LogManager().initialize_base_file_handler("tk-krita")
     except:
         self._use_shotgun = False
Exemple #21
0
def _initialize_manager(plugin_root_path):
    """
    Initializes a ToolkitManager for use in zero-config mode.
    """
    # running in situ as part of zero config. sgtk has already added sgtk
    # to the python path. need to extract the plugin info from info.yml

    # import the yaml parser
    from tank_vendor import yaml

    # build the path to the info.yml file
    plugin_info_yml = os.path.join(plugin_root_path, "info.yml")

    # open the yaml file and read the data
    with open(plugin_info_yml, "r") as plugin_info_fh:
        plugin_info = yaml.load(plugin_info_fh, yaml.SafeLoader)

    base_config = plugin_info["base_configuration"]
    plugin_id = plugin_info["plugin_id"]

    import sgtk

    _initialize_logger(sgtk.LogManager())

    # get a logger for the plugin
    sgtk_logger = sgtk.LogManager.get_logger("plugin")
    sgtk_logger.debug("Booting up toolkit plugin.")

    sgtk_logger.debug("Executable: %s", sys.executable)

    try:
        # Authenticates with Toolkit. If already logged in, this will
        # return the current user.
        user = sgtk.authentication.ShotgunAuthenticator().get_user()
    except sgtk.authentication.AuthenticationCancelled:
        # Show a "Shotgun > Login" menu.
        sgtk_logger.info("Shotgun login was cancelled by the user.")
        return

    # Create a boostrap manager for the logged in user with the plug-in
    # configuration data.
    toolkit_mgr = sgtk.bootstrap.ToolkitManager(user)

    toolkit_mgr.progress_callback = lambda pct, msg: print("{0} - {1}".format(
        int(pct * 100), msg))

    # Pulls the latest Unreal configuration from the master branch.
    toolkit_mgr.base_configuration = base_config
    toolkit_mgr.plugin_id = plugin_id

    return toolkit_mgr
Exemple #22
0
    def _pre_engine_start_callback(self, ctx):
        """
        Called before the engine is started. Closes the proxy connection and removes out log handle.
        """
        import sgtk
        # At this point we need to close the proxy because we can't have two proxies connected
        # at the same sime, especially for logging, to the server.
        # When the engine starts it will set up its own logging.
        self._proxy.close()
        if hasattr(sgtk, "LogManager"):
            sgtk.LogManager().root_logger.removeHandler(self._handler)

        # The desktop engine expects the sgtk instance to have the _desktop_data attribute with
        # the proxy credentials in it.
        ctx.sgtk._desktop_data = self._proxy_data
Exemple #23
0
def bootstrap(data, base_configuration, engine_name, config_data,
              bundle_cache_fallback_paths):
    """
    Bootstraps into sgtk and returns the resulting engine instance.

    :param dict data: The raw payload send down by the client.
    :param str base_configuration: The desired base pipeline configuration's
        uri.
    :param str engine_name: The name of the engine to bootstrap into. This
        is most likely going to be "tk-shotgun"
    :param dict config_data: All relevant pipeline configuration data. This
        dict is keyed by pipeline config entity id, each containing a dict
        that contains, at a minimum, "entity", "lookup_hash", and
        "contents_hash" keys.

    :returns: Bootstrapped engine instance.
    """
    # The local import of sgtk ensures that it occurs after sys.path is set
    # to what the server sent over.
    import sgtk
    sgtk.LogManager().initialize_base_file_handler("tk-shotgun")

    logger = sgtk.LogManager.get_logger(LOGGER_NAME)
    logger.debug("Preparing ToolkitManager for bootstrap.")

    entity = dict(
        type=data["entity_type"],
        id=data["entity_id"],
        project=dict(
            type="Project",
            id=data["project_id"],
        ),
    )

    # Setup the bootstrap manager.
    manager = sgtk.bootstrap.ToolkitManager()
    manager.caching_policy = manager.CACHE_FULL
    manager.allow_config_overrides = False
    manager.plugin_id = "basic.shotgun"
    manager.base_configuration = base_configuration
    manager.pipeline_configuration = config_data["entity"]["id"]
    manager.bundle_cache_fallback_paths = bundle_cache_fallback_paths

    logger.debug("Starting %s using entity %s", engine_name, entity)
    engine = manager.bootstrap_engine(engine_name, entity=entity)
    logger.debug("Engine %s started using entity %s", engine, entity)

    return engine
Exemple #24
0
def start_engine(data):
    """
    Start the tk-desktop engine given a data dictionary like the one passed
    to the launch_python hook.
    """
    sys.path.append(data["core_python_path"])

    # make sure we don't inherit the GUI's pipeline configuration
    os.environ["TANK_CURRENT_PC"] = data["config_path"]

    import sgtk
    sgtk.util.append_path_to_env_var("PYTHONPATH", data["core_python_path"])

    # Initialize logging right away instead of waiting for the engine if we're using a 0.18 based-core.
    # This will also ensure that a crash will be tracked
    if hasattr(sgtk, "LogManager"):
        sgtk.LogManager().initialize_base_file_handler("tk-desktop")

    # If the core supports the shotgun_authentication module and the pickle has
    # a current user, we have to set the authenticated user.
    if hasattr(sgtk, "set_authenticated_user"):
        # Retrieve the currently authenticated user for this process.
        from tank_vendor.shotgun_authentication import ShotgunAuthenticator, deserialize_user
        current_user = ShotgunAuthenticator(
            sgtk.util.CoreDefaultsManager()).get_default_user()

        # If we found no user using the authenticator, we need to use the credentials that
        # came through the environment variable.
        # Also, if the credentials are user-based, we need to disregard what we got and use
        # the credentials from the environment variable. This is required to solve any issues
        # arising from the changes to the session cache changing place in core 0.18.
        if not current_user or current_user.login:
            current_user = deserialize_user(
                os.environ["SHOTGUN_DESKTOP_CURRENT_USER"])
        else:
            # This happens when the user retrieved from the project's core is a script.
            # In that case, we use the script user and disregard who is the current
            # authenticated user at the site level.
            pass

        sgtk.set_authenticated_user(current_user)

    tk = sgtk.sgtk_from_path(data["config_path"])
    tk._desktop_data = data["proxy_data"]
    ctx = tk.context_from_entity("Project", data["project"]["id"])
    engine = sgtk.platform.start_engine("tk-desktop", tk, ctx)

    return engine
 def _emit_log_message(self, handle, record):
     """
     Logs a message to the site engine if available, otherwise logs to disk.
     """
     # If there is no file logger, attempt to send the message to the proxy server.
     if not sgtk.LogManager().base_file_handler:
         # If we can log through the proxy, only do that to avoid
         # duplicate entries in the log file
         try:
             self._project_comm.call_no_response("proxy_log",
                                                 record.levelno, record.msg,
                                                 record.args)
             return
         except Exception:
             # could not log through to the proxy and there is no base file handler. bummer...
             pass
Exemple #26
0
    def __init__(self, parent=None):
        super(Console, self).__init__(parent)

        self.setWindowTitle('Shotgun Desktop Console')
        self.setWindowIcon(QtGui.QIcon(":/tk-desktop/default_systray_icon.png"))

        self.__logs = QtGui.QPlainTextEdit()
        self.__find = QtGui.QLineEdit()
        self.__find_label = QtGui.QLabel()
        layout = QtGui.QVBoxLayout()
        find_layout = QtGui.QHBoxLayout()
        layout.addWidget(self.__logs)
        layout.addLayout(find_layout)
        find_layout.addStretch()
        find_layout.addWidget(self.__find)
        find_layout.addWidget(self.__find_label)
        self.setLayout(layout)

        # configure the text widget
        self.__logs.setReadOnly(True)
        self.__logs.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.__logs.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
        self.__logs.customContextMenuRequested.connect(self.on_logs_context_menu_request)
        self.__logs.setStyleSheet("QPlainTextEdit:focus { border: none; }")
        # configure the find area
        self.__find.setPlaceholderText("Find")
        self.__find_label.setText("No Results")
        self.__find_label.setFixedWidth(60)
        self.__find.returnPressed.connect(self.find)
        self.__pattern = ""
        self.__match_index = 0
        self.__matches = []
        # set shortcut
        find_shortcut = QtGui.QShortcut(QtGui.QKeySequence("Ctrl+F"), self)
        find_shortcut.activated.connect(self.focus_find)
        # load up previous size
        self._settings_manager = settings.UserSettings(sgtk.platform.current_bundle())
        pos = self._settings_manager.retrieve("console.pos", self.pos(), self._settings_manager.SCOPE_GLOBAL)
        size = self._settings_manager.retrieve(
            "console.size", QtCore.QSize(800, 400), self._settings_manager.SCOPE_GLOBAL)

        self.move(pos)
        self.resize(size)

        self.__console_handler = ConsoleLogHandler(self)
        sgtk.LogManager().initialize_custom_handler(self.__console_handler)
    def start_engine(self):
        """
        Bootstraps the engine and launches it.
        """
        # Import Toolkit, but make sure we're not inheriting the parent process's current
        # pipeline configuration.
        sys.path.insert(0, self._core_python_path)
        import sgtk
        del os.environ["TANK_CURRENT_PC"]

        # Connect to the main desktop process so we can send updates to it.
        # We're not guanranteed if the py or pyc file will be passed back to us
        # from the desktop due to write permissions on the folder.
        rpc_lib = imp.load_source("rpc", self._rpc_lib_path)
        self._proxy = rpc_lib.RPCProxy(self._proxy_data["proxy_pipe"],
                                       self._proxy_data["proxy_auth"])
        try:
            # Set up logging with the rpc.
            self._handler = ProxyLoggingHandler(self._proxy)
            sgtk.LogManager().root_logger.addHandler(self._handler)

            # Get the user we should be running as.
            self._user = sgtk.authentication.deserialize_user(
                os.environ["SHOTGUN_DESKTOP_CURRENT_USER"])

            # Prepare the manager based on everything the bootstrap manager expected of us.
            manager = sgtk.bootstrap.ToolkitManager(self._user)
            manager.restore_settings(self._manager_settings)
            manager.pre_engine_start_callback = self._pre_engine_start_callback
            manager.progress_callback = self._progress_callback

            # We're now ready to start the engine.
            return manager.bootstrap_engine("tk-desktop", self._project)
        # Do not attempt to be clever here and catch specific Toolkit exception types.
        # The type information for sgtk.TankError is different after bootstrapping since the
        # core has been swapped, so we can't catch these exceptions.
        finally:
            # Make sure we're closing our proxy so the error reporting,
            # which also creates a proxy, can create its own. If there's an
            # error, make sure we catch it and ignore it. Then the finally
            # can  do its job and propagate the real error if there was one.
            try:
                self._proxy.close()
            except:
                pass
def bootstrap_plugin(plugin_root_path):

    # Add the python subfolder to the PYTHONPATH.
    plugin_python_path = os.path.join(plugin_root_path, "python")
    sys.path.insert(0, plugin_python_path)

    try:
        # When a Toolkit plugin is compiled into a baked plugin for distribution
        # with a DCC, a special module and manifest is created in the build.
        from sgtk_plugin_basic_unreal import manifest
        running_stand_alone = True
    except ImportError:
        manifest = None
        running_stand_alone = False

    if running_stand_alone:
        # running stand alone. import core from the manifest's core path and
        # extract the plugin info from the manifest

        # Retrieve the Shotgun toolkit core included with the plug-in and
        # prepend its python package path to the python module search path.
        # this will allow us to import sgtk
        tk_core_python_path = manifest.get_sgtk_pythonpath(plugin_root_path)
        sys.path.insert(0, tk_core_python_path)

        import sgtk

        _initialize_logger(sgtk.LogManager())

        manager = sgtk.bootstrap.ToolkitManager()
        manager.progress_callback = lambda pct, msg: print(
            "%s - %s" % (int(pct * 100), msg)
        )
        manifest.initialize_manager(manager, plugin_root_path)
    else:
        manager = _initialize_manager(plugin_root_path)

    # synchronous
    manager.bootstrap_engine(
        os.environ.get("SHOTGUN_ENGINE", "tk-unreal"),
        manager.get_entity_from_environment()
    )
    _on_engine_initialized()
Exemple #29
0
def launch_engine():
    # Installs a StreamHandler so we see the server output in the console.
    sgtk.LogManager().initialize_base_file_handler("tk-multi-publish2.test")

    # Set the repo root environment variable that is used by the config.
    repo_root = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..")
    repo_root = os.path.normpath(repo_root)
    os.environ["REPO_ROOT"] = repo_root

    # Authenticate
    user = sgtk.authentication.ShotgunAuthenticator().get_user()
    sg = user.create_sg_connection()

    # Bootstrap
    manager = sgtk.bootstrap.ToolkitManager(user)
    manager.plugin_id = "basic.shell"
    manager.base_configuration = "sgtk:descriptor:path?path=$REPO_ROOT/tests/fixtures/config"
    manager.do_shotgun_config_lookup = False
    manager.progress_callback = progress_callback
    return manager.bootstrap_engine("tk-shell", sg.find_one("Project", []))
def start_toolkit():
    """
    Import Toolkit and start up a tk-maya engine based on
    environment variables.
    """

    # Verify sgtk can be loaded.
    try:
        import sgtk
    except Exception as e:
        OpenMaya.MGlobal.displayError(
            "Shotgun: Could not import sgtk! Disabling for now: %s" % e)
        return

    # start up toolkit logging to file
    sgtk.LogManager().initialize_base_file_handler("tk-maya")

    if os.environ.get("SGTK_LOAD_MAYA_PLUGINS"):
        # Plugins will take care of initializing everything
        start_toolkit_with_plugins()
    else:
        # Rely on the classic bootstrapping method
        start_toolkit_classic()

    # Check if a file was specified to open and open it.
    file_to_open = os.environ.get("SGTK_FILE_TO_OPEN")
    if file_to_open:
        OpenMaya.MGlobal.displayInfo("Shotgun: Opening '%s'..." % file_to_open)
        cmds.file(file_to_open, force=True, open=True)

    # Clean up temp env variables.
    del_vars = [
        "SGTK_ENGINE",
        "SGTK_CONTEXT",
        "SGTK_FILE_TO_OPEN",
        "SGTK_LOAD_MAYA_PLUGINS",
    ]
    for var in del_vars:
        if var in os.environ:
            del os.environ[var]