""" Module for getting information from, setting up and connecting to WingIDE """ import os import sys import _winreg import shutil import filecmp import ConfigParser import logging import pyfbsdk as mobu from RS import Config from RS import Perforce from RS import Globals logging.getLogger(__name__) def SetupDefaultWingIDEPreferences(prefsFile): """ Sets up the default Wing IDE preferences Arguments: prefsFile (string): path to file that has WingIde's preferences Return: tuple (boolean, string): The first value is True or False, depending if the command completed successfully and the second is a string containing an error message if an error was encountered. """ errorMessage = "The {} does not exist".format(prefsFile) if os.path.isfile(prefsFile):# and os.path.getsize(prefsFile): # Wrapping in a try catch because sometimes preferences file can become corrupt try: config = ConfigParser.ConfigParser() config.read(prefsFile) # Turn on passive listen so that we can accept debug connections. config.set('user-preferences', 'debug.passive-listen', True) # Setup our keymapping to the remote script execution. try: keymapOverrideDict = eval(config.get('user-preferences', 'gui.keymap-override')) except ConfigParser.NoOptionError: keymapOverrideDict = {'Ctrl-E': 'ExecuteActiveScript'} config.set('user-preferences', 'gui.keymap-override', keymapOverrideDict) # Custom keys already exist. See if our custom script is in there already. customActionExists = [True for command in keymapOverrideDict.itervalues() if command == 'ExecuteActiveScript'] # Command doesn't exist, so add it. if not customActionExists: keymapOverrideDict['Ctrl-E'] = 'ExecuteActiveScript' config.set('user-preferences', 'gui.keymap-override', keymapOverrideDict) # Write out the preferences. with open(prefsFile, 'w') as prefFile: config.write(prefFile) errorMessage = '' except Exception, error: logging.warning("Wing IDE Error - {}".format(error)) errorMessage = ('Wing IDE preferences file seems to be corrupt. ' 'You will need to load Wing\nopen up preferences, ' 'toggle a setting and apply to fix the preferences file.') return bool(errorMessage), errorMessage def GetWingDirectory(): """ Gets the location where WingIde is installed Return: tuple(string, string): The first value is the path , depending if the command completed successfully and the second is a string containing an error message if an error was encountered. """ reg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) wingHome = "" errorMessage = "" if "wildwest" in __file__.lower() or Config.User.Type in ("Tools", "Programmer"): logging.warning('Could not find an installation path for Wing IDE!') key = None # Check for Wing 5 first. for wingVersion in ("5.0", "4.1"): try: key = _winreg.OpenKey(reg, r'SOFTWARE\Wow6432Node\ARCHAEOPTERYX\WINGIDE\{}\INSTALL'.format(wingVersion), 0, _winreg.KEY_ALL_ACCESS) logging.info("Wing IDE Version {} detected".format(wingVersion)) except: continue wingHome = _winreg.QueryValueEx(key, 'WINGHOME')[0] _winreg.CloseKey(key) _, errorMessage = SetupDefaultWingIDEPreferences(os.path.join(os.environ['USERPROFILE'], 'AppData', 'Roaming', 'Wing IDE {}'.format(wingVersion[0]), 'preferences')) if not key: logging.warning('Wing Ide Error - preferences file not found') return wingHome, errorMessage def SetupWingIDE(): """ Copies the RunFromWing.py file to Wing IDE's scripts directory, so that it can be bound to a hot key. Return: tuple (boolean, string): The first value is True or False, depending if the command completed successfully and the second is a string containing an error message if an error was encountered. """ wingHome, errorMessage = GetWingDirectory() if wingHome: defaultRunFromWingScript = os.path.join(wingHome, 'scripts', 'RunFromWing.py') rockstarRunFromWingScript = os.path.join(Config.Script.Path.Root, 'etc', 'RunFromWing.py') fileState = Perforce.GetFileState(rockstarRunFromWingScript) if fileState: # Is our script the file up-to-date isLatest = Perforce.IsLatest(fileState) # Does wing script exist locally exists = os.path.isfile(defaultRunFromWingScript) # Compare the our script against the Wing IDE script isSame = exists and filecmp.cmp(rockstarRunFromWingScript, defaultRunFromWingScript) # Sync latest version of the script Perforce.Sync(rockstarRunFromWingScript) # override the script in Wing with ours from the Python directory if our script was out of date, the wing # ide script does not exist or the wing ide script does not match our script. if not all((isLatest, exists, isSame)): shutil.copyfile(rockstarRunFromWingScript, defaultRunFromWingScript) return bool(wingHome), errorMessage def ConnectToWing(show=False): """ Connect to Wing IDE for debugging python scripts """ try: import wingdbstub wingdbstub.Ensure() return True except Exception, error: logging.warning("Wing IDE Error - {}".format(error)) return False def OnWatchRunRemoteScriptFileChanged(): """ When the Remote Watch File is updated, execute the contents of the file as a python script in Motion Builder. """ with open(Globals.WingRemoteWatchFile, 'r') as remoteFile: line = remoteFile.readline() silent = "-silent" in line script = line.startswith('-script') reload = line.startswith('-reload') if script or reload: # Attempt to make Wing IDE connection. if '-ignoreWing' not in line: try: import wingdbstub wingdbstub.Ensure() except: print 'Could not connect to Wing IDE!' arg, executable = line.split(';') if not silent: # Force the MotionBuilder Python editor to open. mobu.FBPopNormalTool('Python Editor') print ('Executing script: ', 'Running module: ')[reload], executable if script: Globals.Application.ExecuteScript(executable) else: if executable not in sys.modules: __import__(executable, globals(), locals(), [], -1) else: module = sys.modules[ executable ] reload(module)