123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- import re, os, math
- import nuke, nukescripts
-
-
- class musterSubmit(KellerNukePlugin):
-
- def configurePlugin(self):
- menubar = nuke.menu("Nuke")
- self.m = menubar.addMenu("&Render")
- self.m.addCommand("MusterSubmit", 'musterSubmit.submit()', "ctrl+r")
-
- def unconfigurePlugin(self):
- self.m.removeItem("MusterSubmit")
-
- #############################
- # GLOBALS
- #############################
-
- mstr_server = "192.168.0.251"
- submission_user ="admin"
- password = ""
-
- mrtool = "\\\\hades\\p\\env\\muster9\\Mrtool.exe"
- username = "admin"
- pool = "NukeWin"
- template = "821"
- #nukePath="\\\\hades\\p\\env\\nuke\\_workgroup\\%s.%s\\" %(nuke.NUKE_VERSION_MAJOR,nuke.NUKE_VERSION_MINOR)
- nukePath="\\\\hades\\p\\env\\nuke\\_workgroup\\%s\\" %nuke.NUKE_VERSION_MAJOR
- # Nuke Version
- nukeVer = nuke.env['NukeVersionString']
- nukeExe = "Nuke" + nukeVer[:-2] + ".exe"
-
- # Build env dict for the farm and ignore these entries...
- ignoreEnvEntries = ['PATH', 'NUKE_TEMP_DIR', 'TMP', 'TEMP', 'OCIO', 'ADSKFLEX_LICENSE_FILE', 'FPS', 'SOLIDANGLE_LICENSE', 'foundry_LICENSE',
- 'peregrinel_LICENSE', 'keller_LICENSE', 'QUALM_LICENSE', 'PROGRAMFILES', 'APPDATA', 'COMMONPROGRAMW6432', 'PATHEXT', 'ALLUSERSPROFILE',
- 'PSMODULEPATH', 'PROCESSOR_IDENTIFIER', 'PROCESSOR_ARCHITECTURE', 'LOCALAPPDATA', 'PROCESSOR', 'GUID', 'PYTHONPATH', 'IDEA_INITIAL_DIRECTORY',
- 'ONEDRIVE', 'PYCHARM', 'PYCHARM_HOSTED', 'NUMBER_OF_PROCESSORS', 'PROCESSOR', 'HOMEPATH' ,'COMPUTERNAME', 'USERDOMAIN', 'USERPROFILE','COMPILE_0_1DEV']
-
- ############################
-
-
-
- def get_broken_write_nodes():
- """
- Returns list of all write nodes that refer to non-existing paths (or an empty list).
- If nodes are selected only they will be checked.
- """
-
- nodes = nuke.selectedNodes()
- if not nodes: nodes = nuke.allNodes()
- n = [i for i in nodes if i.Class() == "Write"]
-
- result = []
- for curNode in n:
- fileKnob = curNode['file']
- try:
- if not os.path.exists(os.path.dirname(fileKnob.evaluate())):
- result.append(curNode)
- except:
- pass
-
- return result
-
- def fix_broken_write_nodes():
- """
- Create paths for all (selected) write nodes in case they don't exist yet.
- """
-
- nodes = get_broken_write_nodes()
- for curNode in nodes:
- thePath = os.path.dirname(curNode['file'].evaluate())
- if thePath and not os.path.exists(thePath):
- try:
- os.makedirs(thePath)
- print ("musterSubmit: Info. Created directory "+thePath)
-
- except:
- nuke.message("musterSubmit: Error. Error creating "+thePath)
-
- def _replaceKnobPath(fileknob):
- infile = os.path.normpath(fileknob.getValue()).strip()
- infile = infile.replace("\\", "/")
- infile = infile.replace("p:/", "//hades/p/")
- infile = infile.replace("P:/", "//hades/p/")
- infile = infile.replace("o:/", "//calculon/o/")
- infile = infile.replace("O:/", "//calculon/o/")
-
- return infile
-
- def _replacePathInNodes(root):
- for node in root.nodes():
- if isinstance(node, nuke.Group):
- _replacePathInNodes(node)
- elif node.Class() in ["Read", "Write"]:
-
- newFile = _replaceKnobPath(node["file"])
- node["file"].setValue(newFile)
- print ("musterSubmit: Info. Checking file Path of node %s: %s" % (node.name(), newFile))
-
- def replaceNodeFilePaths():
- r = nuke.root()
- _replacePathInNodes(r)
-
-
-
- def submit(selectedNodes = None):
- """
- Submits a script to Muster. Cross-Platform (Win and MacOS)
- """
- replaceNodeFilePaths()
- # comp saved?
- if not nuke.knob("root.name") or nuke.modified():
- if nuke.ask("Script needs to be saved before rendering.\nSave and continue?"):
- try:
- nuke.scriptSave()
- except RuntimeError:
- # if save dialog was cancelled and script is not untitled we could try to render anyways
- if not nuke.knob("root.name") or not nuke.ask("Could not save script. Try to render anyways?"):
- return
- else:
- return
-
- # get configs from scene
- # TODO: check with KEnv
- # ocio
- if nuke.root()['OCIO_config'].value() == 'custom':
- if nuke.root()['customOCIOConfigPath'].value() != "":
- ocioConfig = nuke.root()['customOCIOConfigPath'].value()
- ocioConfig = ocioConfig.replace("/","\\")
- else:
- ocioConfig = '\\env\\nuke\\_run\\Nuke\\' + nuke.NUKE_VERSION_STRING + '\\plugins\\OCIOConfigs\\configs\\' + \
- nuke.root()['OCIO_config'].value() + '\\config.ocio'
-
- # Nuke Workgroup
- try:
- nukePath=os.environ['NUKE_PATH']
- except:
- # fallback to gen workgroup
- pass
-
-
- # get default render range
- a = nuke.knob("first_frame")
- b = nuke.knob("last_frame")
- start = int(a)
- end = int(b)
- incr = 1
- rangeStr = a+"-"+b
-
- # set packet size automatically to use all available nodes
- # set _max_instances to current size of render farm
- # OVERRIDING PACKET SIZE TO 1, OTHERWISE RENDER FAILS TOO OFTEN!
- #_max_instances = 6
- #_max_psize = 10
- psize = 4
-
- # find packet size so that there is a small remainder
- #_smallest_remainder = 100
- #for i in range(_max_psize+1, 1):
- # _remainder = (end-start+1) % (i * _max_instances)
- # if _remainder <= _smallest_remainder:
- # _smallest_remainder = _remainder
- # psize = i
- # packet size not smaller than 1/15th of frame range
- #psize = max( min(_max_psize, int((end-start+1)/15)), psize)
-
- #Priority:
- prio = 10
-
- #Threads
- threads = 16
-
- #Cache-Limit
- cachelimit = 8192
-
- #Default Folder NukeWin
- parentID = 147
- pool = "NukeWin"
-
- #One Job per Write
- parallel = False
-
- # build panel
- panel = nuke.Panel("Submit to Muster")
- panel.setWidth(500)
- panel.addSingleLineInput("Frames to render:", rangeStr)
- panel.addSingleLineInput("Packet size:", psize)
- panel.addSingleLineInput("Max. instances:", "")
- panel.addSingleLineInput("No. of threads:", threads)
- panel.addSingleLineInput("Ram-Cache Limit:", cachelimit)
- panel.addSingleLineInput("Priority:", prio)
- panel.addSingleLineInput("RenderPool:", pool)
- panel.addEnumerationPulldown("Muster Folder:","NukeWin HOT")
- panel.addSingleLineInput("Workgroup:", nukePath)
- panel.addBooleanCheckBox("Submit one job per Write Node", parallel)
-
- #panel.addSingleLineInput("OCIO Config:", ocioConfig)
- #
-
- panel.addButton("Cancel")
- panel.addButton("OK")
-
- if panel.show() == 0:
- return
-
- mfolder = panel.value("Muster Folder:")
- if mfolder == "HOT":
- parentID = 29037
- elif mfolder == "NukeWin":
- parentID = 147
- else:
- pass
-
- mpool = panel.value("RenderPool:")
- if mpool is not None:
- pool = mpool
- else:
- pass
-
- rangeStr = panel.value("Frames to render:")
- if rangeStr is not None:
- rangeStr = re.sub("[-|-|/]", " ", rangeStr)
- t = rangeStr.split()
- else:
- return
- if len(t) > 0:
- start = int(t[0])
- end = start
- else:
- return
- if len(t) > 1: end = int(t[1])
- if len(t) > 2: incr = int(t[2])
-
- psize = panel.value("Packet size:")
- if psize is not None:
- try:
- psize = int(psize)
- psize = max(1, psize)
- except ValueError:
- psize = 4
- else:
- psize = 4
-
- maxi = panel.value("Max. instances:")
- try:
- maxistr = "-max %i" % (max(0, int(maxi)))
- except ValueError:
- maxistr = ""
-
- prio = panel.value("Priority:")
- if prio is not None:
- try:
- prio = int(prio)
- except ValueError:
- prio = 10
- else:
- prio = 10
-
- threads = panel.value("No. of threads:")
- if threads is not None:
- try:
- threads = int(threads)
- except ValueError:
- threads = 16
- else:
- threads = 16
-
- cache = panel.value("Ram-Cache Limit:")
- if cache is not None:
- try:
- cache = int(cache)
- except ValueError:
- cache = 20000
- else:
- cache = 20000
-
-
- parallel = panel.value("Submit one job per Write Node")
- if parallel is None:
- parallel is False
-
- currNk = nuke.value("root.name")
- nukePath = panel.value("Workgroup:")
-
- if nuke.env["WIN32"]:
- currNk = re.sub(r"^[pP]:", r"//hades/p", currNk)
- currNk = re.sub(r"^[oO]:", r"//calculon/o", currNk)
- currNk = os.path.normpath(currNk)
- currNk = currNk.replace("\\","/")
-
- # -s server
- # -n job name
- # -u user name
- # -sf start frame
- # -b batch submit
- # -ef end frame
- # -pk packet size
- # -bf by frame (frame stepping)
- # -e engine template ID
- # -st numbering step
- # -f file name
- # -pool destination pool
- # -pr priority
- # -max maximum nr of instances
- # -parent 39401 // folder ID
-
- # jobname for later use
- jobname = os.path.basename(nuke.value("root.name")).split(".nk")[0]
- jobtmp = "replaceMe"
-
- #envDict = {"horst":"hemke","peter":"wolf"}
-
- envDict = {key: val for key, val in os.environ.items() if key not in ignoreEnvEntries}
-
- cmd = '%s -s %s -u %s -b -e %s -n %s' % (mrtool, mstr_server, username, template, jobtmp)
- cmd += ' -sf %i -ef %i -bf 1 -st 1' % (int(start), int(end))
- cmd += ' -pk %i -pr %i %s -pool "%s" -parent %i' % (int(psize), int(prio), maxistr, pool, int(parentID))
- cmd += ' -attr "NUKEVERSION" %s 0 -attr "NUKEPATH" %s 0 -attr "NUKERENDERTHREADS" %s 0' % (nukeVer, nukePath, int(threads))
- cmd += ' -attr "NUKECACHELIMIT" %s 0 -attr "NUKEEXEVERSION" %s 0' % (int(cache), nukeExe)
- cmd += ' -attr "environmental_variables" "%s" 0' % (';'.join('{}={}'.format(key, val.replace('/','\\').replace('\\','\\\\')) for key, val in sorted(envDict.items())))
- cmd += ' -f "%s"' % currNk
-
-
- def appendWriteNodes(_nodes):
- writeNodes = list()
- if _nodes is not None:
- for n in _nodes:
- if n.Class() == "Write":
- writeNodes.append(n)
-
- elif n.Class() == "Group":
- writeNodes = writeNodes + appendWriteNodes(n.nodes())
- return writeNodes
-
- if selectedNodes is None:
- selectedNodes = nuke.selectedNodes()
-
- writeNodes = appendWriteNodes(selectedNodes)
- # sort
- selWrites = '__'+'_'.join([node.fullName() for node in sorted(writeNodes)])
-
- if writeNodes:
- if parallel == False:
- cmd += ' -add "-X '+','.join([node.fullName() for node in sorted(writeNodes)])
- rep = jobname+selWrites
- cmd = cmd.replace("replaceMe",str(rep))
- # submit
- print ("musterSubmit: Info. Submitting...")
- print (cmd)
- print (os.system(cmd))
- else:
- for no in sorted(writeNodes):
- cmd += ' -add "-X ' + no.fullName() + '"'
- # change job name
- cmd = cmd.replace("replaceMe", jobname + "__" + no.fullName())
- print ("musterSubmit: Info. Submitting...")
- print (cmd)
-
- # submit
- print (os.system(cmd))
- # change name back for next loop
- cmd = cmd.replace(jobname + "__" + no.fullName(),"replaceMe")
|