暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

musterSubmit.py 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. import re, os, math
  2. import nuke, nukescripts
  3. class musterSubmit(KellerNukePlugin):
  4. def configurePlugin(self):
  5. menubar = nuke.menu("Nuke")
  6. self.m = menubar.addMenu("&Render")
  7. self.m.addCommand("MusterSubmit", 'musterSubmit.submit()', "ctrl+r")
  8. def unconfigurePlugin(self):
  9. self.m.removeItem("MusterSubmit")
  10. #############################
  11. # GLOBALS
  12. #############################
  13. mstr_server = "192.168.0.251"
  14. submission_user ="admin"
  15. password = ""
  16. mrtool = "\\\\hades\\p\\env\\muster9\\Mrtool.exe"
  17. username = "admin"
  18. pool = "NukeWin"
  19. template = "821"
  20. #nukePath="\\\\hades\\p\\env\\nuke\\_workgroup\\%s.%s\\" %(nuke.NUKE_VERSION_MAJOR,nuke.NUKE_VERSION_MINOR)
  21. nukePath="\\\\hades\\p\\env\\nuke\\_workgroup\\%s\\" %nuke.NUKE_VERSION_MAJOR
  22. # Nuke Version
  23. nukeVer = nuke.env['NukeVersionString']
  24. nukeExe = "Nuke" + nukeVer[:-2] + ".exe"
  25. # Build env dict for the farm and ignore these entries...
  26. ignoreEnvEntries = ['PATH', 'NUKE_TEMP_DIR', 'TMP', 'TEMP', 'OCIO', 'ADSKFLEX_LICENSE_FILE', 'FPS', 'SOLIDANGLE_LICENSE', 'foundry_LICENSE',
  27. 'peregrinel_LICENSE', 'keller_LICENSE', 'QUALM_LICENSE', 'PROGRAMFILES', 'APPDATA', 'COMMONPROGRAMW6432', 'PATHEXT', 'ALLUSERSPROFILE',
  28. 'PSMODULEPATH', 'PROCESSOR_IDENTIFIER', 'PROCESSOR_ARCHITECTURE', 'LOCALAPPDATA', 'PROCESSOR', 'GUID', 'PYTHONPATH', 'IDEA_INITIAL_DIRECTORY',
  29. 'ONEDRIVE', 'PYCHARM', 'PYCHARM_HOSTED', 'NUMBER_OF_PROCESSORS', 'PROCESSOR', 'HOMEPATH' ,'COMPUTERNAME', 'USERDOMAIN', 'USERPROFILE','COMPILE_0_1DEV']
  30. ############################
  31. def get_broken_write_nodes():
  32. """
  33. Returns list of all write nodes that refer to non-existing paths (or an empty list).
  34. If nodes are selected only they will be checked.
  35. """
  36. nodes = nuke.selectedNodes()
  37. if not nodes: nodes = nuke.allNodes()
  38. n = [i for i in nodes if i.Class() == "Write"]
  39. result = []
  40. for curNode in n:
  41. fileKnob = curNode['file']
  42. try:
  43. if not os.path.exists(os.path.dirname(fileKnob.evaluate())):
  44. result.append(curNode)
  45. except:
  46. pass
  47. return result
  48. def fix_broken_write_nodes():
  49. """
  50. Create paths for all (selected) write nodes in case they don't exist yet.
  51. """
  52. nodes = get_broken_write_nodes()
  53. for curNode in nodes:
  54. thePath = os.path.dirname(curNode['file'].evaluate())
  55. if thePath and not os.path.exists(thePath):
  56. try:
  57. os.makedirs(thePath)
  58. print ("musterSubmit: Info. Created directory "+thePath)
  59. except:
  60. nuke.message("musterSubmit: Error. Error creating "+thePath)
  61. def _replaceKnobPath(fileknob):
  62. infile = os.path.normpath(fileknob.getValue()).strip()
  63. infile = infile.replace("\\", "/")
  64. infile = infile.replace("p:/", "//hades/p/")
  65. infile = infile.replace("P:/", "//hades/p/")
  66. infile = infile.replace("o:/", "//calculon/o/")
  67. infile = infile.replace("O:/", "//calculon/o/")
  68. return infile
  69. def _replacePathInNodes(root):
  70. for node in root.nodes():
  71. if isinstance(node, nuke.Group):
  72. _replacePathInNodes(node)
  73. elif node.Class() in ["Read", "Write"]:
  74. newFile = _replaceKnobPath(node["file"])
  75. node["file"].setValue(newFile)
  76. print ("musterSubmit: Info. Checking file Path of node %s: %s" % (node.name(), newFile))
  77. def replaceNodeFilePaths():
  78. r = nuke.root()
  79. _replacePathInNodes(r)
  80. def submit(selectedNodes = None):
  81. """
  82. Submits a script to Muster. Cross-Platform (Win and MacOS)
  83. """
  84. replaceNodeFilePaths()
  85. # comp saved?
  86. if not nuke.knob("root.name") or nuke.modified():
  87. if nuke.ask("Script needs to be saved before rendering.\nSave and continue?"):
  88. try:
  89. nuke.scriptSave()
  90. except RuntimeError:
  91. # if save dialog was cancelled and script is not untitled we could try to render anyways
  92. if not nuke.knob("root.name") or not nuke.ask("Could not save script. Try to render anyways?"):
  93. return
  94. else:
  95. return
  96. # get configs from scene
  97. # TODO: check with KEnv
  98. # ocio
  99. if nuke.root()['OCIO_config'].value() == 'custom':
  100. if nuke.root()['customOCIOConfigPath'].value() != "":
  101. ocioConfig = nuke.root()['customOCIOConfigPath'].value()
  102. ocioConfig = ocioConfig.replace("/","\\")
  103. else:
  104. ocioConfig = '\\env\\nuke\\_run\\Nuke\\' + nuke.NUKE_VERSION_STRING + '\\plugins\\OCIOConfigs\\configs\\' + \
  105. nuke.root()['OCIO_config'].value() + '\\config.ocio'
  106. # Nuke Workgroup
  107. try:
  108. nukePath=os.environ['NUKE_PATH']
  109. except:
  110. # fallback to gen workgroup
  111. pass
  112. # get default render range
  113. a = nuke.knob("first_frame")
  114. b = nuke.knob("last_frame")
  115. start = int(a)
  116. end = int(b)
  117. incr = 1
  118. rangeStr = a+"-"+b
  119. # set packet size automatically to use all available nodes
  120. # set _max_instances to current size of render farm
  121. # OVERRIDING PACKET SIZE TO 1, OTHERWISE RENDER FAILS TOO OFTEN!
  122. #_max_instances = 6
  123. #_max_psize = 10
  124. psize = 4
  125. # find packet size so that there is a small remainder
  126. #_smallest_remainder = 100
  127. #for i in range(_max_psize+1, 1):
  128. # _remainder = (end-start+1) % (i * _max_instances)
  129. # if _remainder <= _smallest_remainder:
  130. # _smallest_remainder = _remainder
  131. # psize = i
  132. # packet size not smaller than 1/15th of frame range
  133. #psize = max( min(_max_psize, int((end-start+1)/15)), psize)
  134. #Priority:
  135. prio = 10
  136. #Threads
  137. threads = 16
  138. #Cache-Limit
  139. cachelimit = 8192
  140. #Default Folder NukeWin
  141. parentID = 147
  142. pool = "NukeWin"
  143. #One Job per Write
  144. parallel = False
  145. # build panel
  146. panel = nuke.Panel("Submit to Muster")
  147. panel.setWidth(500)
  148. panel.addSingleLineInput("Frames to render:", rangeStr)
  149. panel.addSingleLineInput("Packet size:", psize)
  150. panel.addSingleLineInput("Max. instances:", "")
  151. panel.addSingleLineInput("No. of threads:", threads)
  152. panel.addSingleLineInput("Ram-Cache Limit:", cachelimit)
  153. panel.addSingleLineInput("Priority:", prio)
  154. panel.addSingleLineInput("RenderPool:", pool)
  155. panel.addEnumerationPulldown("Muster Folder:","NukeWin HOT")
  156. panel.addSingleLineInput("Workgroup:", nukePath)
  157. panel.addBooleanCheckBox("Submit one job per Write Node", parallel)
  158. #panel.addSingleLineInput("OCIO Config:", ocioConfig)
  159. #
  160. panel.addButton("Cancel")
  161. panel.addButton("OK")
  162. if panel.show() == 0:
  163. return
  164. mfolder = panel.value("Muster Folder:")
  165. if mfolder == "HOT":
  166. parentID = 29037
  167. elif mfolder == "NukeWin":
  168. parentID = 147
  169. else:
  170. pass
  171. mpool = panel.value("RenderPool:")
  172. if mpool is not None:
  173. pool = mpool
  174. else:
  175. pass
  176. rangeStr = panel.value("Frames to render:")
  177. if rangeStr is not None:
  178. rangeStr = re.sub("[-|-|/]", " ", rangeStr)
  179. t = rangeStr.split()
  180. else:
  181. return
  182. if len(t) > 0:
  183. start = int(t[0])
  184. end = start
  185. else:
  186. return
  187. if len(t) > 1: end = int(t[1])
  188. if len(t) > 2: incr = int(t[2])
  189. psize = panel.value("Packet size:")
  190. if psize is not None:
  191. try:
  192. psize = int(psize)
  193. psize = max(1, psize)
  194. except ValueError:
  195. psize = 4
  196. else:
  197. psize = 4
  198. maxi = panel.value("Max. instances:")
  199. try:
  200. maxistr = "-max %i" % (max(0, int(maxi)))
  201. except ValueError:
  202. maxistr = ""
  203. prio = panel.value("Priority:")
  204. if prio is not None:
  205. try:
  206. prio = int(prio)
  207. except ValueError:
  208. prio = 10
  209. else:
  210. prio = 10
  211. threads = panel.value("No. of threads:")
  212. if threads is not None:
  213. try:
  214. threads = int(threads)
  215. except ValueError:
  216. threads = 16
  217. else:
  218. threads = 16
  219. cache = panel.value("Ram-Cache Limit:")
  220. if cache is not None:
  221. try:
  222. cache = int(cache)
  223. except ValueError:
  224. cache = 20000
  225. else:
  226. cache = 20000
  227. parallel = panel.value("Submit one job per Write Node")
  228. if parallel is None:
  229. parallel is False
  230. currNk = nuke.value("root.name")
  231. nukePath = panel.value("Workgroup:")
  232. if nuke.env["WIN32"]:
  233. currNk = re.sub(r"^[pP]:", r"//hades/p", currNk)
  234. currNk = re.sub(r"^[oO]:", r"//calculon/o", currNk)
  235. currNk = os.path.normpath(currNk)
  236. currNk = currNk.replace("\\","/")
  237. # -s server
  238. # -n job name
  239. # -u user name
  240. # -sf start frame
  241. # -b batch submit
  242. # -ef end frame
  243. # -pk packet size
  244. # -bf by frame (frame stepping)
  245. # -e engine template ID
  246. # -st numbering step
  247. # -f file name
  248. # -pool destination pool
  249. # -pr priority
  250. # -max maximum nr of instances
  251. # -parent 39401 // folder ID
  252. # jobname for later use
  253. jobname = os.path.basename(nuke.value("root.name")).split(".nk")[0]
  254. jobtmp = "replaceMe"
  255. #envDict = {"horst":"hemke","peter":"wolf"}
  256. envDict = {key: val for key, val in os.environ.items() if key not in ignoreEnvEntries}
  257. cmd = '%s -s %s -u %s -b -e %s -n %s' % (mrtool, mstr_server, username, template, jobtmp)
  258. cmd += ' -sf %i -ef %i -bf 1 -st 1' % (int(start), int(end))
  259. cmd += ' -pk %i -pr %i %s -pool "%s" -parent %i' % (int(psize), int(prio), maxistr, pool, int(parentID))
  260. cmd += ' -attr "NUKEVERSION" %s 0 -attr "NUKEPATH" %s 0 -attr "NUKERENDERTHREADS" %s 0' % (nukeVer, nukePath, int(threads))
  261. cmd += ' -attr "NUKECACHELIMIT" %s 0 -attr "NUKEEXEVERSION" %s 0' % (int(cache), nukeExe)
  262. cmd += ' -attr "environmental_variables" "%s" 0' % (';'.join('{}={}'.format(key, val.replace('/','\\').replace('\\','\\\\')) for key, val in sorted(envDict.items())))
  263. cmd += ' -f "%s"' % currNk
  264. def appendWriteNodes(_nodes):
  265. writeNodes = list()
  266. if _nodes is not None:
  267. for n in _nodes:
  268. if n.Class() == "Write":
  269. writeNodes.append(n)
  270. elif n.Class() == "Group":
  271. writeNodes = writeNodes + appendWriteNodes(n.nodes())
  272. return writeNodes
  273. if selectedNodes is None:
  274. selectedNodes = nuke.selectedNodes()
  275. writeNodes = appendWriteNodes(selectedNodes)
  276. # sort
  277. selWrites = '__'+'_'.join([node.fullName() for node in sorted(writeNodes)])
  278. if writeNodes:
  279. if parallel == False:
  280. cmd += ' -add "-X '+','.join([node.fullName() for node in sorted(writeNodes)])
  281. rep = jobname+selWrites
  282. cmd = cmd.replace("replaceMe",str(rep))
  283. # submit
  284. print ("musterSubmit: Info. Submitting...")
  285. print (cmd)
  286. print (os.system(cmd))
  287. else:
  288. for no in sorted(writeNodes):
  289. cmd += ' -add "-X ' + no.fullName() + '"'
  290. # change job name
  291. cmd = cmd.replace("replaceMe", jobname + "__" + no.fullName())
  292. print ("musterSubmit: Info. Submitting...")
  293. print (cmd)
  294. # submit
  295. print (os.system(cmd))
  296. # change name back for next loop
  297. cmd = cmd.replace(jobname + "__" + no.fullName(),"replaceMe")