├── plugin-walker.py └── README.markdown /plugin-walker.py: -------------------------------------------------------------------------------- 1 | # Automagic plugin load script. 2 | # Version 1.0.0 3 | # Maintainer andrew.bunday 4 | # Walks from a plugin directory root adding subdirs to the path. 5 | # Assumes file lives in the root of the plugin directory ie. 6 | # 7 | # ./plugins/ 8 | # -> init.py 9 | # -> myplugin/1.1 10 | # -> myplugin/1.0 11 | # -> myplugin2/1.0 12 | # 13 | # 14 | # Builds a list of the plugins residing in the current directory. Assumes that plugins live in a subdir 15 | # called ./pluginname/version/*files. 16 | # 17 | # Unless a version for the plugin has been set in the nuke command path we use the last version in 18 | # the sorted list of versions available. 19 | # 20 | # Currently makes the assumption that only one version of plugin will be required within a scenefile... tbc. 21 | # 22 | # When the plugin is added to the nuke plugin path only python scripts are added to python's sys.path 23 | # this is an over-optimisation, but appears to be harmless.... or possibly not since J_Ops stores its python in 24 | # a "py" dir. 25 | 26 | import os, re 27 | import inspect 28 | import nuke 29 | import logging 30 | import sys 31 | 32 | logging.basicConfig(level=logging.ERROR) 33 | 34 | def addPathToPlugins( plugin_path ): 35 | 36 | for dirpath, dirnames, filenames in os.walk( plugin_path, followlinks=True ): 37 | logging.debug( "---" ) 38 | logging.debug( dirpath ) 39 | logging.debug( dirnames ) 40 | logging.debug( filenames ) 41 | 42 | if re.match(".*/python$", dirpath) : #or re.match(".*/py$", dirpath): # this is required for us to source jops directly 43 | nuke.pluginAddPath( dirpath, addToSysPath=True ) 44 | else: 45 | nuke.pluginAddPath( dirpath, addToSysPath=False ) 46 | 47 | if "__init__.py" in filenames: # then this must be a python module to be added to sys.path 48 | logging.debug( "Python module detected %s. Adding parent to syspath %s" % (os.path.basename(dirpath), os.path.dirname(dirpath)) ) 49 | sys.path.append( os.path.dirname(dirpath) ) 50 | 51 | location = os.path.split( inspect.getsourcefile( addPathToPlugins ) )[0] 52 | 53 | files = os.listdir( location ) 54 | plugins = {} 55 | 56 | for file in files: 57 | if os.path.isdir( os.path.join( location, file ) ): 58 | plugins[ file ] = os.path.join( location, file ) 59 | 60 | for plugin_name in plugins: 61 | available_versions = os.listdir( plugins[ plugin_name ] ) 62 | available_versions.sort() 63 | 64 | plugin_version = os.getenv( plugin_name.upper() ) 65 | 66 | if not plugin_version or ( plugin_version not in available_versions ) : 67 | plugin_version = available_versions[-1] 68 | 69 | plugin_path = os.path.join( plugins[ plugin_name ], plugin_version ) 70 | 71 | addPathToPlugins( plugin_path ) 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Nuke Plugin Walker 2 | ================== 3 | 4 | ## The Short Description 5 | 6 | 7 | An auto discovery and loading script for The Foundry's Nuke Compositing Application. 8 | 9 | Supports adding of plugin paths to the nuke pluginpath, python sys.path and controlled versioning of plugins. 10 | 11 | 12 | ## A Slightly Longer Description 13 | 14 | This simple python snippet makes my life much easier when packaging up new plugins/gizmos for Nuke. The main inspiration for doing this came from becoming annoyed by artists adding each new plugin to their menu.py scripts in their home directories and by each plugin having this codeblock in its init.py: 15 | 16 | for path in nuke.pluginPath(): 17 | if os.path.exists(path+"/myplugin/py"): 18 | sys.path.append(path+"/myplugin/py") 19 | if os.path.exists(path+"/../myplugins/py"): 20 | sys.path.append(path+"/py") 21 | if os.path.exists(path+"/../myplugin/ndk"): 22 | nuke.pluginAddPath(path+"/ndk") 23 | if os.path.exists(path+"/../myplugin/icons"): 24 | nuke.pluginAddPath(path+"/icons") 25 | 26 | This script *removes* the requirement for each plugin to feature this snippet and also provides handling for multiple versioning of plugins installed on the system. 27 | 28 | 29 | ## Simple Usage Instructions 30 | 31 | Your plugins should be organised in the fairly standard layout of: 32 | 33 | MyPlugin// 34 | docs/ 35 | icons/ 36 | ndk/ 37 | py 38 | menu.py 39 | init.py 40 | 41 | *The python directory may be called either py/python.* 42 | 43 | The init.py file should be left empty unless you perform some initialization for your plugin here. The gumph involving lots of **os.path.exists** calls listed earlier shouldn't be put in. 44 | 45 | All of your plugins should live under the same plugin directory, or else you should have a copy of the plugin walker copied into each of the directories listed in your NUKE_PATH. 46 | 47 | ### Versioning 48 | 49 | Since the walker supports versioning of your plugins you can place each major.minor release in a sub-directory under the plugin name. To ensure that Nuke auto-loads the walker script it's renamed to init.py upon installation. 50 | 51 | Here's an example: 52 | 53 | ./plugins/ 54 | -> init.py 55 | -> myplugin/1.1 56 | -> myplugin/1.0 57 | -> myplugin2/1.0 58 | 59 | When the walker runs it first looks under its current directory for the plugin names and versions. It will then attempt to load the one with the latest release. 60 | 61 | If a specific version is required then it can be set via an environment variable. 62 | 63 | export MYPLUGIN=1.0 64 | 65 | The environment variable is the name of the plugin converted to uppercase. 66 | 67 | #### Patch Versions 68 | 69 | Personally we only allow major.minor versions of plugins to visible to the end users. This means that they never see patch versions on the system and usually we'll overwrite these with the next release. 70 | 71 | For us the patch versions are controlled and search-able via the system package manager. ie. 72 | 73 | Package Name Package Version 74 | nuke6.3-myplugin1.0 1.0.2-baseblack-r1 75 | 76 | *** 77 | --------------------------------------------------------------------------------