def execute(self, source_path, target_path, read_only=False, **kwargs): """ Main hook entry point :param source_path: String Source file path to copy :param target_path: String Target file path to copy to """ # create the folder if it doesn't exist dirname = os.path.dirname(target_path) if not os.path.isdir(dirname): old_umask = os.umask(0) # os.makedirs(dirname, 0777) # USE JSTOOLS INSTEAD dd_jstools_utils.makedir_with_jstools(dirname) os.umask(old_umask) current_permission = os.stat(source_path).st_mode if read_only: # make file read_only ro_mask = 0777 ^ (stat.S_IWRITE | stat.S_IWGRP | stat.S_IWOTH) permission = current_permission & ro_mask else: # make file writeable by user+group rw_mask = stat.S_IWRITE | stat.S_IWGRP permission = current_permission | rw_mask copy_file(source_path, target_path, permission)
def _copy_outsource_to_work(self, settings, item): work_template = item.properties.get("work_template") if not work_template: self.logger.debug("No work template set on the item. " "Skipping copy file to publish location.") return # by default, the path that was collected for publishing outsource_files = [item.properties.path] # ---- copy the outsource files to the work location if not item.properties.fields: self.logger.debug("No item fields supplied from collector." "Required to resolve template paths.") return for outsource_file in outsource_files: # if not work_template.validate(outsource_file): # self.logger.warning( # "Work file '%s' did not match work template '%s'. " # "Publishing in place." % (outsource_file, work_template) # ) # return # work_fields = work_template.get_fields(outsource_file) # missing_keys = work_template.missing_keys(work_fields) # if missing_keys: # self.logger.warning( # "Work file '%s' missing keys required for the publish " # "template: %s" % (outsource_file, missing_keys) # ) # return work_file = work_template.apply_fields(item.properties.fields) self.logger.debug(">>>>> work_file: %s" % str(work_file)) self.logger.debug(">>>>> outsource_file: %s" % str(outsource_file)) # copy the file try: work_folder = os.path.dirname(work_file) ensure_folder_exists(work_folder) copy_file(outsource_file, work_file) except Exception: raise Exception( "Failed to copy outsource file from '%s' to '%s'.\n%s" % (outsource_file, work_file, traceback.format_exc())) self.logger.debug("Copied work file '%s' to work file '%s'." % (outsource_file, work_file))
def _copy_work_to_publish(self, settings, item): """ This method handles exporting a layer and copying it to a designated publish location. This method requires a "publish_template" be set on the supplied item. The method will not attempt to copy files if any of the above requirements are not met. If the requirements are met, the file will ensure the publish path folder exists and then copy the file to that location. """ krita_app = Krita.instance() node = item.properties["node"] session_path = item.properties["session_path"] active_doc = item.properties.get("session_document") export_path = self.get_export_path(settings, item) export_path_folder = os.path.dirname(export_path) ensure_folder_exists(export_path_folder) # this is so the publisher picks the right location for this layer item.properties.path = export_path # export the layer with _batch_mode(True): self._export_layer(node, export_path, active_doc) publish_path = self.get_publish_path(settings, item) # if the publish path is different that were the layer was exported # copy the file over if not os.path.normpath(publish_path) == os.path.normpath(export_path): publish_folder = os.path.dirname(publish_path) ensure_folder_exists(publish_folder) # copy the file to the publish location try: copy_file(export_path, publish_path) self.logger.debug( "Copied exported files '%s' to publish folder '%s'." % (export_path, publish_path)) except Exception: raise TankError( "Failed to copy exported file from '%s' to '%s'.\n%s" % (export_path, publish_path, traceback.format_exc())) else: self.logger.debug("Skipping copy file to publish location.") # this is so the publisher picks the right location for this layer item.properties.path = publish_path item.set_thumbnail_from_path(publish_path)
def _copy_files(self, dest_path, item): """ This method handles copying an item's path(s) to a designated location. If the item has "sequence_paths" set, it will attempt to copy all paths assuming they meet the required criteria. """ publisher = self.parent # ---- get a list of files to be copied if item.properties["is_sequence"]: work_files = item.properties.get("sequence_paths", []) else: work_files = [item.properties["path"]] # ---- copy the work files to the publish location processed_files = [] for work_file in work_files: if item.properties["is_sequence"]: frame_num = publisher.util.get_frame_number(work_file) dest_file = publisher.util.get_path_for_frame(dest_path, frame_num) else: dest_file = dest_path # If the file paths are the same, skip... if work_file == dest_file: continue # copy the file try: dest_folder = os.path.dirname(dest_file) ensure_folder_exists(dest_folder) copy_file(work_file, dest_file, permissions=stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) except Exception as e: raise Exception( "Failed to copy work file from '%s' to '%s'.\n%s" % (work_file, dest_file, traceback.format_exc()) ) self.logger.debug( "Copied work file '%s' to '%s'." % (work_file, dest_file) ) processed_files.append(dest_file) return processed_files
def copy_files(self, src_files, dest_path, seal_files=False, is_sequence=False): """ This method handles copying an item's path(s) to a designated location. If the item has "sequence_paths" set, it will attempt to copy all paths assuming they meet the required criteria. """ publisher = self.parent logger = publisher.logger # ---- copy the src files to the dest location processed_files = [] for src_file in src_files: if is_sequence: frame_num = self.get_frame_number(src_file) dest_file = self.get_path_for_frame(dest_path, frame_num) else: dest_file = dest_path # If the file paths are the same, lock permissions if src_file == dest_file: filesystem.freeze_permissions(dest_file) continue # copy the file try: dest_folder = os.path.dirname(dest_file) filesystem.ensure_folder_exists(dest_folder) filesystem.copy_file(src_file, dest_file, permissions=stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH, seal=seal_files) except Exception as e: raise Exception("Failed to copy file from '%s' to '%s'.\n%s" % (src_file, dest_file, traceback.format_exc())) logger.debug("Copied file '%s' to '%s'." % (src_file, dest_file)) processed_files.append(dest_file) return processed_files
def _copy_work_to_publish(self, settings, item): """ This method handles copying work file path(s) to a designated publish location. This method requires a "work_template" and a "publish_template" be set on the supplied item. The method will handle copying the "path" property to the corresponding publish location assuming the path corresponds to the "work_template" and the fields extracted from the "work_template" are sufficient to satisfy the "publish_template". The method will not attempt to copy files if any of the above requirements are not met. If the requirements are met, the file will ensure the publish path folder exists and then copy the file to that location. If the item has "sequence_paths" set, it will attempt to copy all paths assuming they meet the required criteria with respect to the templates. """ #### IMPORTANT #### # Due to a quirk in the system, this function hooked here, # but executes from a call in the app_store #### /IMPORTANT #### # ---- ensure templates are available work_template = item.properties.get("work_template") if not work_template: self.logger.debug("No work template set on the item. " "Skipping copy file to publish location.") return publish_template = item.properties.get("publish_template") if not publish_template: self.logger.debug("No publish template set on the item. " "Skipping copying file to publish location.") return # ---- get nuke script to copy and its copy destination work_file = item.properties.get("path") publish_file = item.properties.get("copy_destination") # check for missing keys to make 100% sure the file can be copied work_fields = item.properties.get("work_fields") missing_keys = publish_template.missing_keys(work_fields) if missing_keys: self.logger.warning( "Work file '%s' missing keys required for the publish " "template: %s" % (work_file, missing_keys)) return # final sanity check to prevent overwriting backup files # if a file already exists, create a duplicate. if not os.path.exists(publish_file): self.logger.debug("Creating Backup of Nuke Script") pass else: self.logger.warning( "A backup by this name already exists. Creating a copy...") copy_number = 1 while os.path.exists(publish_file) == True: prev_copy_version = "_copy%s.nk" % str(copy_number - 1).zfill(3) copy_version = "_copy%s.nk" % str(copy_number).zfill(3) if re.search(r"v\d\d\d\.nk", publish_file[-7:]): publish_file = publish_file.replace(".nk", copy_version) copy_number += 1 elif re.search(r"_copy\d\d\d\.nk", publish_file[-11:]): publish_file = publish_file.replace( prev_copy_version, copy_version) copy_number += 1 else: pass # copy the file try: publish_folder = os.path.dirname(publish_file) ensure_folder_exists(publish_folder) copy_file(work_file, publish_file) except Exception: raise Exception("Failed to copy work file from '%s' to '%s'.\n%s" % (work_file, publish_file, traceback.format_exc())) self.logger.debug("Copied work file '%s' to publish file '%s'." % (work_file, publish_file))
def _copy_work_to_publish(self, settings, item): """ This method handles copying work file path(s) to a designated publish location. This method requires a "work_template" and a "publish_template" be set on the supplied item. The method will handle copying the "path" property to the corresponding publish location assuming the path corresponds to the "work_template" and the fields extracted from the "work_template" are sufficient to satisfy the "publish_template". The method will not attempt to copy files if any of the above requirements are not met. If the requirements are met, the file will ensure the publish path folder exists and then copy the file to that location. If the item has "sequence_paths" set, it will attempt to copy all paths assuming they meet the required criteria with respect to the templates. """ # ---- ensure templates are available work_template = item.properties.get("work_template") if not work_template: self.logger.debug( "No work template set on the item. " "Skipping copy file to publish location." ) return publish_template = self.get_publish_template(settings, item) if not publish_template: self.logger.debug( "No publish template set on the item. " "Skipping copying file to publish location." ) return # ---- get a list of files to be copied # by default, the path that was collected for publishing work_files = [item.properties.path] # if this is a sequence, get the attached files if "sequence_paths" in item.properties: work_files = item.properties.get("sequence_paths", []) if not work_files: self.logger.warning( "Sequence publish without a list of files. Publishing " "the sequence path in place: %s" % (item.properties.path,) ) return # ---- copy the work files to the publish location for work_file in work_files: if not work_template.validate(work_file): self.logger.warning( "Work file '%s' did not match work template '%s'. " "Publishing in place." % (work_file, work_template) ) return work_fields = work_template.get_fields(work_file) missing_keys = publish_template.missing_keys(work_fields) if missing_keys: self.logger.warning( "Work file '%s' missing keys required for the publish " "template: %s" % (work_file, missing_keys) ) return publish_file = publish_template.apply_fields(work_fields) # copy the file try: publish_folder = os.path.dirname(publish_file) ensure_folder_exists(publish_folder) copy_file(work_file, publish_file) except Exception, e: raise Exception( "Failed to copy work file from '%s' to '%s'.\n%s" % (work_file, publish_file, traceback.format_exc()) ) self.logger.debug( "Copied work file '%s' to publish file '%s'." % (work_file, publish_file) )
def publish(self, settings, item): """ Executes the publish logic for the given item and settings. :param settings: Dictionary of Settings. The keys are strings, matching the keys returned in the settings property. The values are `Setting` instances. :param item: Item to process """ publisher = self.parent path = item.properties.get("path") publish_info = self._get_publish_path(settings, item) publish_name = publish_info[0] publish_path = publish_info[1] publish_folder = os.path.dirname(publish_path) ensure_folder_exists(publish_folder) if 'Texture Folder' in self.get_publish_type(settings, item)[0]: try: udims = publisher.util.get_frame_sequences(path) if udims: for (inFile, seq) in udims: match = re.search(r'%(\d+)d', inFile) if match: glob_path = inFile.split(match.group(0)) else: glob_path = os.path.splitext(inFile) glob_path_m = glob_path[0][:-1] if "_" or "." in glob_path[0][-1] else glob_path[0] match_texturename = re.search(r'([^_|.]+)$', glob_path_m) if match_texturename: for in_frame in glob.glob(inFile.replace(match.group(0), '*')): mt = in_frame.replace(glob_path[0], "") out_frame = os.path.splitext(publish_path)[0] out_frame = "%s_%s.%s" % (out_frame, match_texturename.group(0), mt) if not os.path.exists(out_frame): copy_file(in_frame, out_frame) publish_path = os.path.dirname(publish_path) except Exception: raise Exception( "Failed to copy sequence from '%s' to '%s'.\n%s" % (path, publish_folder, traceback.format_exc()) ) else: try: match = re.search(r'%(\d+)d', path) if match: for in_frame in glob.glob(path.replace(match.group(0), '*')): out_frame = publish_path % int(in_frame.replace(path.split(match.group(0))[0], '').split(".")[0]) if not os.path.exists(out_frame): copy_file(in_frame, out_frame) else: copy_file(path, publish_path) except Exception: raise Exception( "Failed to copy sequence from '%s' to '%s'.\n%s" % (path, publish_folder, traceback.format_exc()) ) self.logger.debug( "@@@ R8S Custom @@@ This files needs copying " "from '%s' to '%s' before publish." % (path, publish_path)) item.properties['path'] = publish_path # ---- determine the information required to publish # We allow the information to be pre-populated by the collector or a # base class plugin. They may have more information than is available # here such as custom type or template settings. publish_path = self.get_publish_path(settings, item) publish_type = self.get_publish_type(settings, item)[0] publish_version = self.get_publish_version(settings, item) publish_dependencies = self.get_publish_dependencies(settings, item) publish_user = self.get_publish_user(settings, item) # if the parent item has a publish path, include it in the list of # dependencies if "sg_publish_path" in item.parent.properties: publish_dependencies.append(item.parent.properties.sg_publish_path) # handle copying of work to publish if templates are in play self._copy_work_to_publish(settings, item) # arguments for publish registration self.logger.info("Registering publish...") publish_data = { "tk": publisher.sgtk, "context": item.context, "comment": item.description, "path": publish_path, "name": publish_name, "created_by": publish_user, "version_number": publish_version, "thumbnail_path": item.get_thumbnail_as_path(), "published_file_type": publish_type, "dependency_paths": publish_dependencies } # log the publish data for debugging self.logger.debug( "Populated Publish data...", extra={ "action_show_more_info": { "label": "Publish Data", "tooltip": "Show the complete Publish data dictionary", "text": "<pre>%s</pre>" % (pprint.pformat(publish_data),) } } ) # create the publish and stash it in the item properties for other # plugins to use. item.properties.sg_publish_data = sgtk.util.register_publish( **publish_data) self.logger.info("Publish registered!") self.logger.debug( "Shotgun Publish data...", extra={ "action_show_more_info": { "label": "Shotgun Publish Data", "tooltip": "Show the complete Shotgun Publish Entity dictionary", "text": "<pre>%s</pre>" % (pprint.pformat(item.properties.sg_publish_data),) } } )