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")
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
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()
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]
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
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)
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")
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)
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)
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
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()
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!")
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
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
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
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
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
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()
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]