def json_audit(): project = Project() environment = Environment() asset_dir = project.get_assets_dir() failed_str = "" for i, asset in enumerate(project.list_assets(AssetType.PROP)): try: asset_obj = project.get_body(asset) element_obj = asset_obj.get_element(Department.MODEL, force_create=True) element_path = element_obj.checkout( environment.get_current_username()) checkout.non_gui_open(element_path, asset) json_exporter_non_gui.exportProp(asset_obj) except Exception, err: error_str = "" error_str += "\nError exporting JSON for {0}".format(asset) error_str += "\n" + traceback.format_exc() print error_str failed_str += error_str continue
def publish_hda(): project = Project() environment = Environment() if publish_window.published: user = publish_window.user comment = publish_window.comment if is_asset: if asset_name in project.list_assets(): body = project.get_asset(asset_name) if os.path.exists(src): if body is not None: if Element.DEFAULT_NAME in body.list_elements(Department.ASSEMBLY): #save node definition asset.type().definition().updateFromNode(asset) asset.matchCurrentDefinition() element = body.get_element(Department.ASSEMBLY, Element.DEFAULT_NAME) dst = element.publish(user, src, comment) #Ensure file has correct permissions try: os.chmod(dst, 0660) except: pass hou.hda.uninstallFile(src, change_oplibraries_file=False) saveFile = asset_name + "_assembly_main.hdanc" dst = os.path.join(environment.get_assembly_dir(), saveFile) hou.hda.installFile(dst) else: hou.ui.displayMessage("File does not exist")
def go(): global checkout_window project = Project() environment = Environment() nodes = hou.selectedNodes() if len(nodes) == 1: #if selected node is digital asset if nodes[0].type().definition() is not None: asset = nodes[0] asset_name = nodes[0].type().name() #get name of asset index = asset_name.find("_main") asset_name = asset_name[:index] src = nodes[0].type().definition().libraryFilePath() current_user = environment.get_current_username() if asset_name in project.list_assets(): body = project.get_asset(asset_name) if os.path.exists(src): if body is not None: if Element.DEFAULT_NAME in body.list_elements(Department.ASSEMBLY): element = body.get_element(Department.ASSEMBLY, Element.DEFAULT_NAME) element_path = element.checkout(current_user) hou.hda.uninstallFile(src, change_oplibraries_file=False) hou.hda.installFile(element_path) asset.allowEditingOfContents() hou.ui.displayMessage("Checkout Successful!", title='Success!') elif len(nodes) > 1: hou.ui.displayMessage("Only one node can be selected for checkout") else: checkout_window = CheckoutWindow(hou.ui.mainQtWindow(), [Department.LIGHTING, Department.FX]) checkout_window.finished.connect(checkout_shot)
def __init__(self, parent, renderNodes): super(ExportDialog, self).__init__() self.parent = parent self.project = Project() self.environment = Environment() self.renderNodes = renderNodes self.initUI()
def publish_hda(): project = Project() environment = Environment() if publish_window.published: user = publish_window.user comment = publish_window.comment if is_asset: if asset_name in project.list_assets(): body = project.get_asset(asset_name) if os.path.exists(src): if body is not None: if Element.DEFAULT_NAME in body.list_elements( Department.ASSEMBLY): #save node definition asset.type().definition().updateFromNode(asset) asset.matchCurrentDefinition() element = body.get_element(Department.ASSEMBLY, Element.DEFAULT_NAME) dst = element.publish(user, src, comment) #Ensure file has correct permissions try: os.chmod(dst, 0660) except: pass hou.hda.uninstallFile(src, change_oplibraries_file=False) saveFile = asset_name + "_assembly_main.hdanc" dst = os.path.join(environment.get_assembly_dir(), saveFile) hou.hda.installFile(dst) else: hou.ui.displayMessage("File does not exist")
def rollback_hda(): filepath = rollback_window.result if filepath is not None: environment = Environment() hou.hda.uninstallFile(src, change_oplibraries_file=False) dst = os.path.join(environment.get_hda_dir(), asset_name) hou.hda.installFile(dst) message_gui.info('Rollback successful')
def rego(): ''' reassembles the currently selected node. That means leaving all of the shop nets in place but throwing out the geo and bringing it in fresh. ''' selection = hou.selectedNodes() if len(selection) > 1: message_gui.error('Please only select one item') return if len(selection) <1: message_gui.error('Please select an item to be reassembled') return hda = selection[0] name = hda.type().name() index = name.rfind('_') main = name[index:] asset_name = name[:index] if main.find('_main') == -1: message_gui.error('There was something wrong with the name. Try tabbing in the asset again and trying one more time.') return project = Project() environment = Environment() username = project.get_current_username() asset = project.get_asset(asset_name) assembly = asset.get_element(Department.ASSEMBLY) # Checkout assembly checkout_file = checkout.checkout_hda(hda, project, environment) reassemble(hda, project, environment, assembly, asset, checkout_file)
def publish_hda(publishWindow, selectedHDA, src): project = Project() environment = Environment() if publishWindow.published: user = publishWindow.user comment = publishWindow.comment hdaName = selectedHDA.type().name() department = publishWindow.elementName # TODO: UGLY HOTFIX FOR OLD ASSEMBLY & TOOL ASSETS asset_name = hdaName.replace("_" + department, "") if department not in [Department.ASSEMBLY, Department.HDA] else hdaName.replace("_main", "") body = project.get_body(asset_name) if body is None: message_gui.error("Asset not found in pipe.") return if os.path.exists(src): try: #save node definition this is the same as the Save Node Type menu option. Just to make sure I remember how this works - We are getting the definition of the selected hda and calling the function on it passing in the selected hda. We are not calling the funciton on the selected hda. selectedHDA.type().definition().updateFromNode(selectedHDA) except hou.OperationFailed, e: message_gui.error('There was a problem publishing the HDA to the pipeline.\n', details=str(e)) return try: selectedHDA.matchCurrentDefinition() except hou.OperationFailed, e: message_gui.warning('There was a problem while trying to match the current definition. It\'s not a critical problem but it is a little troubling. Take a look at it and see if you can resolve the problem. Rest assured that the publish did work though', details=str(e))
def checkout_hda_go(hda=None): global checkout_window project = Project() environment = Environment() if hda is None: nodes = hou.selectedNodes() if len(nodes) == 1: hda = nodes[0] elif len(nodes) > 1: message_gui.error('Only one node can be selected for checkout') return else: message_gui.error('You need to select an asset node to checkout') return if hda.type().definition() is not None: result = checkout_hda(hda, project, environment) if result is not None: print('checkout successful') #I think having the node unlock is visual que enough that the checkout was fine. Mostly it's annoying to have the window there. And we have a window that will let them know if it didn't work. #message_gui.info('Checkout Successful!', title='Success!') else: message_gui.error('Checkout Failed', title='Failure :()') else: message_gui.error('Node is not a digital asset') return
def checkout_shot_go(): global checkout_window project = Project() environment = Environment() checkout_window = CheckoutWindow(hou.ui.mainQtWindow(), [Department.LIGHTING, Department.FX]) checkout_window.finished.connect(checkout_shot)
def audit(): project = Project() environment = Environment() asset_dir = project.get_assets_dir() for i, asset in enumerate(project.list_assets(AssetType.PROP)): asset_obj = project.get_body(asset) element_obj = asset_obj.get_element(Department.MODEL, force_create=True) element_path = element_obj.checkout(environment.get_current_username()) #cmds.file(rename='/tmp/lol'+str(i)+'.mb') #cmds.file(save=True) checkout.non_gui_open(element_path, asset) print 'Done'
def post_assemble(): mari.projects.close() asset_name = mari_assemble_dialog.result print asset_name if asset_name is None: return # Set up the project and environment project = Project() environment = Environment() # get the username and asset username = project.get_current_username() asset = project.get_asset(asset_name) # get the texture element and check it out texture = asset.get_element(Department.TEXTURE) checkout_file = texture.checkout(username) # Get the path to the directory with all of the alembics model = asset.get_element(Department.MODEL) cache = model.get_cache_dir() geo_files = [ x for x in os.listdir(model.get_cache_dir()) if not os.path.isdir(x) ] # Remove anything that is not an alemibic file for file_path in list(geo_files): if (not str(file_path).lower().endswith('.abc')): geo_files.remove(file_path) if len(geo_files) > 1: result = message_gui.light_error( 'There are multiple alembic files in ' + str(file_path) + ' and there should only be one.\nWould you like to continue anyways?\nIt might not work.' ) if not result: return elif len(geo_files) > 1: message_gui.error( 'There is not an alembic cache for this asset. Make sure that the model has been published in Maya and that the static alembic has been exported.' ) return geo_file_path = os.path.join(cache, geo_files[0]) mari.projects.create( texture.get_long_name(), geo_file_path, [], [], dict(), [ { '/': mari.geo.GEOMETRY_IMPORT_DONT_MERGE_CHILDREN }, ]) # At this point there should be no files left to add but if there are then the user was warned about it and we can go ahead and try to load those in. # This was from when we exported a bunch of alembics from Maya instead of just one. And since it shouldn't get called unless something goes wrong I figure it might be interesting to see what would happen if something goes wrong so we might as well leave it. for i in range(1, len(geo_files)): geo_file_path = os.path.join(cache, geo_files[i]) mari.geo.load(geo_file_path) print 'Loaded ' + geo_file_path
def non_gui_publish_hda(hda=None,comment='N/A'): if hda is None: print ('Error with asset') project = Project() environment = Environment() user = environment.get_current_username() hdaName = hda.type().name() department=None if str(hda) not in Department.ALL: print 'v1 asset' department=Department.ASSEMBLY else: department=str(hda) asset_name = hdaName.replace("_" + department, "") if department not in [Department.ASSEMBLY, Department.HDA] else hdaName.replace("_main", "") body = project.get_body(asset_name) if body is None: message_gui.error('No asset in pipe') return #TODO: publish tools if body.is_tool(): print (asset_name+' is tool') return department=Department.HDA hda_src = hda.type().definition().libraryFilePath() print hda_src element = body.get_element(department, Element.DEFAULT_NAME,force_create=True) try: hda.type().definition().updateFromNode(hda) except hou.OperationFailed, e: message_gui.error('There was a problem publishing the HDA to the pipeline.\n', details=str(e)) return
def go(): parent = QtGui.QApplication.activeWindow() if mari.projects.current() is None: message_gui.error( 'You need to have a project open in order to publish it.') return # Get the file location of the mari archive so that the publish windown will get the hightlight right. project_name = mari.projects.current().name() src = project_name index = project_name.find('_texture') if index > 0: environment = Environment() workspace = environment.get_user_workspace() src = os.path.join(workspace, project_name, project_name + '.mra') global mari_publish_dialog mari_publish_dialog = PublishWindow(src, parent, [Department.TEXTURE]) mari_publish_dialog.finished.connect(post_publish)
def post_publish(): element = mari_publish_dialog.result if mari_publish_dialog.published: #save the file project = mari.projects.current() project_id = project.uuid() export_images.go() project.save() project.close() #Publish user = mari_publish_dialog.user src = mari_publish_dialog.src comment = mari_publish_dialog.comment env = Environment() user_dir = env.get_user_workspace() archive_file = os.path.join(user_dir, str(src) + '.mra') mari.projects.archive(project_id, archive_file) dst = element.publish(user, archive_file, comment) #Ensure file has correct permissions try: os.chmod(dst, 0660) except: pass #Delete Temp file try: os.remove(archive_file) except: print 'There was an error while removing the temp file.' pass remove = message_gui.yes_or_no( 'The Mari Project is safely published. Would you like to remove the project from your Mari cache?' ) if remove: mari.projects.remove(project_id)
def go(): parent = maya_main_window() filePath = cmds.file(q=True, sceneName=True) if not filePath: filePath = Environment().get_user_workspace() filePath = os.path.join(filePath, 'untitled.mb') filePath = pipeline_io.version_file(filePath) cmds.file(rename=filePath) cmds.file(save=True) global maya_publish_dialog maya_publish_dialog = PublishWindow(filePath, parent, [Department.MODEL, Department.RIG, Department.LAYOUT, Department.ANIM, Department.CFX, Department.CYCLES]) maya_publish_dialog.finished.connect(post_publish)
def commit_conversions(): # Find all boxes that have nodes that were made by the conversion script boxes = [] for item in hou.selectedItems(): if not isinstance(item, hou.NetworkBox): continue # If the box doesn't have two nodes in it, it's definitely not ours nodes = item.nodes() if len(nodes) != 2: continue # If neither is named _new and/or neither is named _old, it's not one of ours if not "_new" in nodes[0].name() and not "_new" in nodes[1].name(): continue if not "_old" in nodes[0].name() and not "_old" in nodes[1].name(): continue # If the assets are not named the same, it's not one of ours print nodes[0].name()[:-4] print nodes[1].name()[:-4] if nodes[0].name()[:-4] != nodes[1].name()[:-4]: continue # If it passed the tests, add it to the list of network boxes we can work with boxes.append(item) print boxes # Don't go on unless there's a valid network box if len(boxes) < 1: error_message("There aren't any network boxes created by the conversion script.") return for box in boxes: old_node = next((node for node in box.nodes() if "_old" in node.name()), None) new_node = next((node for node in box.nodes() if "_new" in node.name()), None) old_hda = old_node.type().definition() old_hda.setIcon(Environment().get_project_dir() + '/byu-pipeline-tools/assets/images/icons/tool-icons/1.png') publish.non_gui_publish_go(old_node, "Converted to V2") for child in new_node.allSubChildren(): if "_material" in child.type().name() or "_modify" in child.type().name(): publish.non_gui_publish_go(child, "Converted from V1")
def assemble_hda(): asset_name = checkout_window.result if asset_name is None: return project = Project() environment = Environment() username = project.get_current_username() asset = project.get_asset(asset_name) assembly = asset.get_element(Department.ASSEMBLY) # Checkout assembly checkout_file = assembly.checkout(username) if asset.get_type() == AssetType.SET: assemble_set(project, environment, assembly, asset, checkout_file) else: assemble(project, environment, assembly, asset, checkout_file)
return sys._getframe(1).f_code.co_name def super_print(message): with open(os.path.join(Project().get_users_dir(), Project().get_current_username(), "houdini_log.txt"), "a+") as f: print(message) sys.stdout.flush() f.write("\n" + str(datetime.datetime.now()) + "\n") f.write(message) f.flush() # DEBUGGING END # I set this sucker up as a singleton. It's a matter of preference. this = sys.modules[__name__] # The source HDA's are currently stored inside the pipe source code. hda_path = os.path.join(Environment().get_project_dir(), "byu-pipeline-tools", "houdini-tools", "otls") # We define the template HDAs definitions here, for use in the methods below hda_definitions = { Department.MATERIAL: hou.hdaDefinition(hou.sopNodeTypeCategory(), "byu_material", os.path.join(hda_path, "byu_material.hda")), Department.MODIFY: hou.hdaDefinition(hou.sopNodeTypeCategory(), "byu_modify", os.path.join(hda_path, "byu_modify.hda")), Department.HAIR: hou.hdaDefinition(hou.objNodeTypeCategory(), "byu_hair", os.path.join(hda_path, "byu_hair.hda")), Department.CLOTH: hou.hdaDefinition(hou.objNodeTypeCategory(), "byu_cloth", os.path.join(hda_path, "byu_cloth.hda")) } # The order in which these nodes appear is the order they will be created in byu_geo_departments = [Department.MODIFY, Department.MATERIAL] byu_character_departments = [Department.HAIR, Department.CLOTH] hda_dir = Environment().get_hda_dir()
class ExportDialog(QtWidgets.QWidget): finished = QtCore.Signal() def __init__(self, parent, renderNodes): super(ExportDialog, self).__init__() self.parent = parent self.project = Project() self.environment = Environment() self.renderNodes = renderNodes self.initUI() def initUI(self): # Window layout self.setFixedSize(360, 420) self.setWindowTitle('Confirm Export') main_layout = QtWidgets.QVBoxLayout() self.setLayout(main_layout) # Job Name Input Widget self.jobName = QtWidgets.QLineEdit('JobName') self.jobName.selectAll() name_layout = QtWidgets.QHBoxLayout() name_layout.addWidget(QtWidgets.QLabel('Job Name:')) name_layout.addWidget(self.jobName) main_layout.addLayout(name_layout) # Number of Cores Input Widget self.numCores = QtWidgets.QLineEdit('4') coresLayout = QtWidgets.QHBoxLayout() coresLayout.addWidget(QtWidgets.QLabel('Number of Cores:')) coresLayout.addWidget(self.numCores) main_layout.addLayout(coresLayout) # Priority and Start Time # Priority self.priority = QtWidgets.QComboBox() priority_opt = [ 'Very Low', 'Low', 'Medium', 'High', 'Very High', 'Critical' ] for opt in priority_opt: self.priority.addItem(opt) self.priority.setCurrentIndex(2) # Begin time self.delay = QtWidgets.QComboBox() delay_opts = ['Immediate', 'Manual', 'Delayed'] for opt in delay_opts: self.delay.addItem(opt) self.delay.currentIndexChanged.connect(self.delaytime) # Combo box options layout opts_layout = QtWidgets.QHBoxLayout() opts_layout.addWidget(QtWidgets.QLabel('Priority:')) opts_layout.addWidget(self.priority) opts_layout.addWidget(QtWidgets.QLabel('Begin:')) opts_layout.addWidget(self.delay) opts_layout.addStretch() main_layout.addLayout(opts_layout) # Time-frame selection for delayed jobs self.delay_time = QtWidgets.QLineEdit('5') self.delay_unit = QtWidgets.QComboBox() delay_unit_opts = ['mins', 'hours', 'days'] for opt in delay_unit_opts: self.delay_unit.addItem(opt) self.delay_unit.setCurrentIndex(0) # Delay time layout self.delay_layout = QtWidgets.QHBoxLayout() self.delay_layout.addWidget(QtWidgets.QLabel('Delay time:')) self.delay_layout.addWidget(self.delay_time) self.delay_layout.addWidget(self.delay_unit) self.delay_layout.addStretch() self.delaytime(0) main_layout.addLayout(self.delay_layout) # Mantra node selection list self.select = QtWidgets.QListWidget() self.select.setSelectionMode( QtWidgets.QAbstractItemView.ExtendedSelection) for node in self.renderNodes: item = QtWidgets.QListWidgetItem(node.name()) self.select.addItem(item) # must come after adding to widget item.setSelected(True) main_layout.addWidget(self.select) # Buttons self.export_btn = QtWidgets.QPushButton('Export') self.export_btn.clicked.connect(self.export) self.cancel_btn = QtWidgets.QPushButton('Cancel') self.cancel_btn.clicked.connect(self.close) btn_layout = QtWidgets.QHBoxLayout() btn_layout.addWidget(self.cancel_btn) btn_layout.addWidget(self.export_btn) main_layout.addLayout(btn_layout) # Show/Hide the delay-time options def delaytime(self, index): i = 0 items = self.delay_layout.count() while i < items: item = self.delay_layout.itemAt(i).widget() if item: item.setVisible(index == 2) i = i + 1 # Export selected mantra nodes for rendering def export(self): self.close() # Get user, project, and time info so we can make a temp folder user = self.environment.get_current_username() projectName = self.project.get_name().lower() time_now = datetime.datetime.now() #Make a temp folder for the rib files based on the user and the current time ribDir = self.project.get_project_dir( ) + '/ribs/' + user + '_' + time_now.strftime('%m%d%y_%H%M%S') print 'ribDir', ribDir, ' renderNodes size: ', len(self.renderNodes) os.makedirs(ribDir) # Sanitize job title title = re.sub(r'[{}"\']', '', str(self.jobName.text())).strip(' \t\n\r') if len(title) == 0: title = self.empty_text numCores = int( re.sub(r'[{}"\']', '', str(self.numCores.text())).strip(' \t\n\r')) if numCores < 1: numCores = 1 # This job we send to tractor job = author.Job() job.title = title job.priority = self.priority.currentIndex() path = '/opt/pixar/RenderManProServer-21.5/bin/' job.envkey = [ 'setenv PATH=' + path + ' RMANTREE=/opt/pixar/RenderManProServer-21.5' ] job.service = 'PixarRender' job.comment = 'Spooled by ' + user # Loop through each frame of our nodes and create frame tasks and append it to the job script for index, node in enumerate(self.renderNodes): # Make sure this node was selected for export print node.name() if self.select.item(index).isSelected(): name = node.name() validFrameRange = node.parm('trange').eval() if validFrameRange == 0: start = int(hou.frame()) end = int(hou.frame()) step = 1 else: start = int(node.parm('f1').eval()) end = int(node.parm('f2').eval()) step = int(node.parm('f3').eval()) task = author.Task() task.title = '%s [%d-%d]' % (name, start, end) oldOutputMode = node.parm('rib_outputmode').eval() try: oldDiskFile = node.parm('soho_diskfile').expression() useExpression = True print 'We are getting rid of expressiion' except: oldDiskFile = node.parm('soho_diskfile').eval() useExpression = False print 'we didn\'t get rid of them' # Activate rib output node.parm('rib_outputmode').set(True) node.parm('soho_diskfile').deleteAllKeyframes() node.parm('soho_diskfile').set(ribDir + ('/%s_$F04.rib' % name)) print 'start rib making' script = os.path.join(self.project.get_project_dir(), 'byu-pipeline-tools', 'houdini-tools', 'parallelRibs', 'taskDistribution.sh') subprocess.call([ 'sh', script, str(start), str(end), str(node.path()), str(saveHipRenderCopy()), str(numCores) ]) print 'finish rib making' # Loop through every frame in framerange for frame in range(start, end + 1, step): subtask = author.Task() subtask.title = 'Frame %04d' % (frame) ribFile = '%s/%s_%04d.rib' % (ribDir, name, frame) print 'Here is the rib file ', ribFile # Commands for Debugging cmdPATH = author.Command() cmdPATH.argv = ['echo', '${PATH}'] cmdRMANTREE = author.Command() cmdRMANTREE.argv = ['echo', '${RMANTREE}'] printenv = author.Command() printenv.argv = ['printenv'] # subtask.addCommand(cmdPATH) # subtask.addCommand(cmdRMANTREE) # subtask.addCommand(printenv) # Real Commands command = author.Command() command.argv = ['prman', '-progress', ribFile] command.service = 'PixarRender' subtask.addCommand(command) task.addChild(subtask) job.addChild(task) # Restore rib output node.parm('soho_outputmode').set(oldOutputMode) if useExpression: node.parm('soho_diskfile').setExpression(oldDiskFile) else: node.parm('soho_diskfile').set(oldDiskFile) command = author.Command() command.argv = ['rm', '-rf', ribDir] job.addCleanup(command) # print 'This is the new job script \n', job.asTcl() # Attempt to spool job, with the option to keep trying choice = True while choice: try: job.spool() message_gui.info('Job sent to Tractor!') break except Exception as err: choice = message_gui.yes_or_no( 'We ran into this problem while spooling the job:\nWould you like to try again?', details=str(err), title='Continue?') #Cleanup ifd files, if they didn't want to retry if not choice: shutil.rmtree(ribDir)