def publish(self, settings, item): """ Executes the publish logic for the given item and settings. :param settings: Dictionary of Settings. The keys are strings, matching the keys returned in the settings property. The values are `Setting` instances. :param item: Item to process """ publisher = self.parent # get the path in a normalized state. no trailing separator, separators # are appropriate for current os, no double separators, etc. path = sgtk.util.ShotgunPath.normalize(_session_path()) # ensure the session is saved in its current state alias_api.save_file() # get the path to a versioned copy of the file. version_path = publisher.util.get_version_path(path, "v001") # save to the new version path alias_api.save_file_as(version_path) self.logger.info( "A version number has been added to the Alias file...") self.logger.info(" Alias file path: %s" % (version_path, ))
def open_save_as_dialog(self): """ Launch a Qt file browser to select a file, then save the supplied project to that path. """ from sgtk.platform.qt import QtGui # Alias doesn't appear to have a "save as" dialog accessible via # python. so open our own Qt file dialog. file_dialog = QtGui.QFileDialog( parent=self.get_parent_window(), caption="Save As", directory=os.path.expanduser("~"), filter="Alias file (*.wire)", ) file_dialog.setLabelText(QtGui.QFileDialog.Accept, "Save") file_dialog.setLabelText(QtGui.QFileDialog.Reject, "Cancel") file_dialog.setOption(QtGui.QFileDialog.DontResolveSymlinks) file_dialog.setOption(QtGui.QFileDialog.DontUseNativeDialog) if not file_dialog.exec_(): return path = file_dialog.selectedFiles()[0] if os.path.splitext(path)[-1] != ".wire": path = "{0}.wire".format(path) if path: alias_api.save_file_as(path)
def save_file_as(self, path): """ Convenience function to call the Alias Python API to save the file and ensure the context is saved for the current stage. :param path: the file path to save. :type path: str """ status = alias_api.save_file_as(path) if status != int(alias_api.AlStatusCode.Success): self.logger.error( "Alias Python API Error: save_file_as('{}') returned non-success status code {}" .format(path, status)) # Save context for the current stage that was updated self.save_context_for_stage()
def validate(self, settings, item): """ Validates the given item to check that it is ok to publish. Returns a boolean to indicate validity. :param settings: Dictionary of Settings. The keys are strings, matching the keys returned in the settings property. The values are `Setting` instances. :param item: Item to process :returns: True if item is valid, False otherwise. """ publisher = self.parent path = _session_path() # ---- ensure the session has been saved if not path: # the session still requires saving. provide a save button. # validation fails. error_msg = "The Alias session has not been saved." self.logger.error(error_msg, extra=_get_save_as_action()) raise Exception(error_msg) # ---- check the session against any attached work template # get the path in a normalized state. no trailing separator, # separators are appropriate for current os, no double separators, # etc. path = sgtk.util.ShotgunPath.normalize(path) # if the session item has a known work template, see if the path # matches. if not, warn the user and provide a way to save the file to # a different path work_template = item.properties.get("work_template") if work_template: if not work_template.validate(path): self.logger.warning( "The current session does not match the configured work " "file template.", extra={ "action_button": { "label": "Save File", "tooltip": "Save the current Alias session to a " "different file name", # will launch wf2 if configured "callback": _get_save_as_action(), } }, ) else: self.logger.debug( "Work template configured and matches session file.") else: self.logger.debug("No work template configured.") # ---- see if the version can be bumped post-publish # check to see if the next version of the work file already exists on # disk. if so, warn the user and provide the ability to jump to save # to that version now (next_version_path, version) = self._get_next_version_info(path, item) if next_version_path and os.path.exists(next_version_path): # determine the next available version_number. just keep asking for # the next one until we get one that doesn't exist. while os.path.exists(next_version_path): (next_version_path, version) = self._get_next_version_info( next_version_path, item) error_msg = "The next version of this file already exists on disk." self.logger.error( error_msg, extra={ "action_button": { "label": "Save to v%s" % (version, ), "tooltip": "Save to the next available version number, " "v%s" % (version, ), "callback": lambda: alias_api.save_file_as(next_version_path), } }, ) raise Exception(error_msg) # ---- populate the necessary properties and call base class validation # populate the publish template on the item if found publish_template_setting = settings.get("Publish Template") publish_template = publisher.engine.get_template_by_name( publish_template_setting.value) if publish_template: item.properties["publish_template"] = publish_template # set the session path on the item for use by the base plugin validation # step. NOTE: this path could change prior to the publish phase. item.properties["path"] = path # run the base class validation return super(AliasSessionPublishPlugin, self).validate(settings, item)
def execute(self, operation, file_path, context=None, parent_action=None, file_version=None, read_only=None, **kwargs): """ Main hook entry point :param operation: String Scene operation to perform :param file_path: String File path to use if the operation requires it (e.g. open) :param context: Context The context the file operation is being performed in. :param parent_action: This is the action that this scene operation is being executed for. This can be one of: - open_file - new_file - save_file_as - version_up :param file_version: The version/revision of the file to be opened. If this is 'None' then the latest version should be opened. :param read_only: Specifies if the file should be opened read-only or not :returns: Depends on operation: 'current_path' - Return the current scene file path as a String 'reset' - True if scene was reset to an empty state, otherwise False all others - None """ self.parent.engine._stop_watching = True try: if operation == "current_path": return alias_api.get_current_path() elif operation == "open": # if the current file is an empty file, we can erase it and open the new file instead if alias_api.is_empty_file(): alias_api.open_file(file_path, new_stage=False) # otherwise, ask the use what he'd like to do else: open_in_current_stage = ( self.parent.engine.open_delete_stages_dialog()) if open_in_current_stage == QtGui.QMessageBox.Cancel: return elif open_in_current_stage == QtGui.QMessageBox.No: alias_api.open_file(file_path, new_stage=True) else: alias_api.reset() alias_api.open_file(file_path, new_stage=False) elif operation == "save": alias_api.save_file() elif operation == "save_as": alias_api.save_file_as(file_path) elif operation == "reset": # do not reset the file if we try to open another one as we have to deal with the stages an resetting # the current session will delete all the stages if parent_action == "open_file": return True if alias_api.is_empty_file() and len( alias_api.get_stages()) == 1: alias_api.reset() return True else: open_in_current_stage = self.parent.engine.open_delete_stages_dialog( new_file=True) if open_in_current_stage == QtGui.QMessageBox.Cancel: return False elif open_in_current_stage == QtGui.QMessageBox.No: stage_name = uuid.uuid4().hex alias_api.create_stage(stage_name) else: alias_api.reset() return True finally: self.parent.engine._stop_watching = False if operation in ["save_as", "prepare_new", "open"]: self.parent.engine.save_context_for_stage(context)