def main(): bolt.deprintOn = opts.debug if len(extra) > 0: return # useful for understanding context of bug reports if opts.debug or hasattr(sys, 'frozen'): # Standalone stdout is NUL no matter what. Redirect it to stderr. # Also, setup stdout/stderr to the debug log if debug mode / standalone before wxPython is up errLog = open(os.path.join(os.getcwdu(), u'BashBugDump.log'), 'w') sys.stdout = errLog sys.stderr = errLog old_stderr = errLog if opts.debug: dump_environment() if opts.Psyco: try: import psyco psyco.full() except: pass # ensure we are in the correct directory so relative paths will work properly if hasattr(sys, "frozen"): pathToProg = os.path.dirname( unicode(sys.executable, sys.getfilesystemencoding())) else: pathToProg = os.path.dirname( unicode(sys.argv[0], sys.getfilesystemencoding())) if pathToProg: os.chdir(pathToProg) del pathToProg # Detect the game we're running for import bush if opts.debug: print u'Searching for game to manage:' ret = bush.setGame(opts.gameName, opts.oblivionPath) if ret != False: # False == success if len(ret) != 1: if len(ret) == 0: msgtext = _( u"Wrye Bash could not find a game to manage. Please use -o command line argument to specify the game path" ) else: msgtext = _( u"Wrye Bash could not determine which game to manage. The following games have been detected, please select one to manage." ) msgtext += u'\n\n' msgtext += _( u'To prevent this message in the future, use the -g command line argument to specify the game' ) try: # First try using wxPython import wx class AppReturnCode(object): def __init__(self, default=None): self.value = default def get(self): return self.value def set(self, value): self.value = value class GameSelect(wx.Frame): def __init__(self, gameNames, callback): wx.Frame.__init__(self, None, wx.ID_ANY, u'Wrye Bash') self.callback = callback self.panel = panel = wx.Panel(self, wx.ID_ANY) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add( wx.TextCtrl(panel, wx.ID_ANY, msgtext, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_BESTWRAP), 1, wx.GROW | wx.ALL, 5) for gameName in gameNames: gameName = gameName[0].upper() + gameName[1:] sizer.Add(wx.Button(panel, wx.ID_ANY, gameName), 0, wx.GROW | wx.ALL ^ wx.TOP, 5) button = wx.Button(panel, wx.ID_CANCEL, _(u'Quit')) button.SetDefault() sizer.Add(button, 0, wx.GROW | wx.ALL ^ wx.TOP, 5) self.Bind(wx.EVT_BUTTON, self.OnButton) panel.SetSizer(sizer) def OnButton(self, event): if event.GetId() != wx.ID_CANCEL: self.callback( self.FindWindowById(event.GetId()).GetLabel()) self.Close(True) _app = wx.App(False) retCode = AppReturnCode() frame = GameSelect(ret, retCode.set) frame.Show() frame.Center() _app.MainLoop() del _app retCode = retCode.get() if retCode is None: return # Add the game to the command line, so restarting uses it sys.argv = sys.argv + ['-g', retCode] bush.setGame(retCode, opts.oblivionPath) except: # No good with wxPython, use Tkinter instead # Python mode, use Tkinter here, since we don't know for sure if wx is present import Tkinter root = Tkinter.Tk() frame = Tkinter.Frame(root) frame.pack() class onQuit(object): def __init__(self): self.canceled = False def onClick(self): self.canceled = True root.destroy() quit = onQuit() button = Tkinter.Button(frame, text=_(u'Quit'), fg='red', command=quit.onClick, pady=15, borderwidth=5, relief=Tkinter.GROOVE) button.pack(fill=Tkinter.BOTH, expand=1, side=Tkinter.BOTTOM) class onClick(object): def __init__(self, gameName): self.gameName = gameName def onClick(self): sys.argv = sys.argv + ['-g', self.gameName] bush.setGame(self.gameName, opts.oblivionPath) root.destroy() for gameName in ret: text = gameName[0].upper() + gameName[1:] command = onClick(gameName).onClick button = Tkinter.Button(frame, text=text, command=command, pady=15, borderwidth=5, relief=Tkinter.GROOVE) button.pack(fill=Tkinter.BOTH, expand=1, side=Tkinter.BOTTOM) w = Tkinter.Text(frame) w.insert(Tkinter.END, msgtext) w.config(state=Tkinter.DISABLED) w.pack() root.mainloop() if quit.canceled: return del Tkinter # Unload TKinter, it's not needed anymore else: bush.setGame(ret[0], opts.oblivionPath) if opts.bashmon: # ensure the console is set up properly import ctypes ctypes.windll.kernel32.AllocConsole() sys.stdin = open('CONIN$', 'r') sys.stdout = open('CONOUT$', 'w', 0) sys.stderr = open('CONOUT$', 'w', 0) # run bashmon and exit import bashmon bashmon.monitor(0.25) #--Call monitor with specified sleep interval return #--Initialize Directories and some settings # required before the rest has imported SetUserPath(u'bash.ini', opts.userPath) isUAC = False try: # Force Python mode if CBash can't work with this game bolt.CBash = opts.mode if bush.game.esp.canCBash else 1 import bosh isUAC = bosh.testUAC(opts.oblivionPath) bosh.initBosh(opts.personalPath, opts.localAppDataPath, opts.oblivionPath) bosh.exe7z = bosh.dirs['compiled'].join(bosh.exe7z).s # if HTML file generation was requested, just do it and quit if opts.genHtml is not None: msg1 = _(u"generating HTML file from: '%s'") % opts.genHtml msg2 = _(u'done') try: print msg1 except UnicodeError: print msg1.encode('mbcs') import belt bolt.WryeText.genHtml(opts.genHtml) try: print msg2 except UnicodeError: print msg2.encode('mbcs') return import basher import barb import balt except (bolt.PermissionError, bolt.BoltError) as e: # try really hard to be able to show the error in the GUI try: if 'basher' not in locals(): # we get here if initBosh threw import basher import barb import balt except: raise e if opts.debug: if hasattr(sys, 'frozen'): app = basher.BashApp() else: app = basher.BashApp(False) bolt.deprintOn = True else: app = basher.BashApp() balt.showError(None, u'%s' % e) app.MainLoop() raise e except (ImportError, StandardError) as e: # try really hard to be able to show the error in any GUI try: o = StringIO.StringIO() traceback.print_exc(file=o) msg = o.getvalue() o.close() msg = (_(u'Error! Unable to start Wrye Bash.') + u'\n\n' + _(u'Please ensure Wrye Bash is correctly installed.') + u'\n\n\n%s') % msg print msg if hasattr(sys, 'frozen'): # WBSA we've disabled TKinter, since it's not required, use wx # here instead import wx class ErrorMessage(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, u'Wrye Bash') self.panel = panel = wx.Panel(self, wx.ID_ANY) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add( wx.TextCtrl(panel, wx.ID_ANY, msg, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_BESTWRAP), 1, wx.GROW | wx.ALL, 5) button = wx.Button(panel, wx.ID_CANCEL, _(u'Quit')) button.SetDefault() sizer.Add(button, 0, wx.GROW | wx.ALL ^ wx.TOP, 5) self.Bind(wx.EVT_BUTTON, self.OnButton) panel.SetSizer(sizer) def OnButton(self, event): self.Close(True) _app = wx.App(False) frame = ErrorMessage() frame.Show() frame.Center() _app.MainLoop() del _app return else: # Python mode, use Tkinter import Tkinter root = Tkinter.Tk() frame = Tkinter.Frame(root) frame.pack() button = Tkinter.Button(frame, text=_(u"QUIT"), fg="red", command=root.destroy, pady=15, borderwidth=5, relief=Tkinter.GROOVE) button.pack(fill=Tkinter.BOTH, expand=1, side=Tkinter.BOTTOM) w = Tkinter.Text(frame) w.insert(Tkinter.END, msg) w.config(state=Tkinter.DISABLED) w.pack() root.mainloop() return except StandardError as y: print 'An error has occured with Wrye Bash, and could not be displayed.' print 'The following is the error that occured while trying to display the first error:' try: print y traceback.format_exc() except: print ' An error occured while trying to display the second error.' print 'The following is the error that could not be displayed:' raise e if not oneInstanceChecker(): return atexit.register(exit) basher.InitSettings() basher.InitLinks() basher.InitImages() #--Start application if opts.debug: if hasattr(sys, 'frozen'): # Special case for py2exe version app = basher.BashApp() # Regain control of stdout/stderr from wxPython sys.stdout = old_stderr sys.stderr = old_stderr else: app = basher.BashApp(False) else: app = basher.BashApp() import wx wxver = wx.version() if not u'unicode' in wxver.lower() and not u'2.9' in wxver: # Can't use translatable strings, because they'd most likely end up being in unicode! if not balt.askYes( None, 'Warning: you appear to be using a non-unicode version of wxPython (%s). This will cause problems! It is highly recommended you use a unicode version of wxPython instead. Do you still want to run Wrye Bash?' % wxver, 'Warning: Non-Unicode wxPython detected', ): return sysVersion = (sys.version_info[0], sys.version_info[1], sys.version_info[2]) if sysVersion < ( 2, 6 ): #nasty, may cause failure in oneInstanceChecker but better than bash failing to open things for no (user) apparent reason such as in 2.5.2 and under. bolt.close_fds = False if sysVersion[:2] == (2, 5): run = balt.askYes( None, _(u"Warning: You are using a python version prior to 2.6 and there may be some instances that failures will occur. Updating to Python 2.7x is recommended but not imperative. Do you still want to run Wrye Bash right now?" ), _(u"Warning OLD Python version detected")) else: run = balt.askYes( None, _(u"Warning: You are using a Python version prior to 2.5x which is totally out of date and ancient and Bash will likely not like it and may totally refuse to work. Please update to a more recent version of Python(2.7x is preferred). Do you still want to run Wrye Bash?" ), _(u"Warning OLD Python version detected")) if not run: return # process backup/restore options # quit if either is true, but only after calling both quit = cmdBackup() quit = cmdRestore() or quit if quit: return global basherImported basherImported = True basher.isUAC = isUAC if isUAC: uacRestart = False if not opts.noUac and not opts.uac: # Show a prompt asking if we should restart in Admin Mode message = _( u"Wrye Bash needs Administrator Privileges to make changes to the %(gameName)s directory. If you do not start Wrye Bash with elevated privileges, you will be prompted at each operation that requires elevated privileges." ) % { 'gameName': bush.game.name } title = _(u'UAC Protection') if balt.canVista: admin = _(u'Run with Administrator Privileges') readme = bosh.dirs['mopy'].join( u'Docs', u'Wrye Bash General Readme.html') if readme.exists(): readme = u'file:///' + readme.s.replace( u'\\', u'/').replace(u' ', u'%20') else: # Fallback to SVN repository readme = u"http://wrye-bash.github.io/docs/Wrye%20Bash%20General%20Readme.html" readme += '#trouble-permissions' uacRestart = balt.vistaDialog( None, message=message, buttons=[ (True, u'+' + admin), (False, _(u'Run normally')), ], title=title, expander=[ _(u'How to avoid this message in the future'), _(u'Less information'), (_(u'Use one of the following command line switches:') + u'\n\n' + _(u'--no-uac: always run normally') + u'\n' + _(u'--uac: always run with Admin Privileges') + u'\n\n' + _(u'See the <A href="%(readmePath)s">readme</A> for more information.' ) % { 'readmePath': readme }) ], ) else: uacRestart = balt.askYes( None, message + u'\n\n' + _(u'Start Wrye Bash with Administrator Privileges?'), title) elif opts.uac: uacRestart = True if uacRestart: basher.appRestart = True basher.uacRestart = True return app.Init() app.MainLoop()
print 'An error has occured with Wrye Bash, and could not be ' \ 'displayed.' print 'The following is the error that occured while trying to ' \ 'display the first error:' try: print y traceback.format_exc() except: print ' An error occured while trying to display the second '\ 'error.' print 'The following is the error that could not be displayed:' raise e if not oneInstanceChecker(): return atexit.register(exit) basher.InitSettings() basher.InitLinks() basher.InitImages() #--Start application if opts.debug: if hasattr(sys, 'frozen'): # Special case for py2exe version app = basher.BashApp() # Regain control of stdout/stderr from wxPython sys.stdout = old_stderr sys.stderr = old_stderr else: app = basher.BashApp(False) else: app = basher.BashApp()
def main(): bolt.deprintOn = opts.debug if len(extra) > 0: return # useful for understanding context of bug reports if opts.debug or hasattr(sys, 'frozen'): # Standalone stdout is NUL no matter what. Redirect it to stderr. # Also, setup stdout/stderr to the debug log if debug mode / # standalone before wxPython is up errLog = open(os.path.join(os.getcwdu(), u'BashBugDump.log'), 'w') sys.stdout = errLog sys.stderr = errLog old_stderr = errLog if opts.debug: dump_environment() # ensure we are in the correct directory so relative paths will work # properly if hasattr(sys, "frozen"): pathToProg = os.path.dirname( unicode(sys.executable, bolt.Path.sys_fs_enc)) else: pathToProg = os.path.dirname(unicode(sys.argv[0], bolt.Path.sys_fs_enc)) if pathToProg: os.chdir(pathToProg) del pathToProg # Detect the game we're running for --------------------------------------- import bush if opts.debug: print u'Searching for game to manage:' # set the Bash ini global in bass bashIni = bass.GetBashIni() ret = bush.setGame(opts.gameName, opts.oblivionPath, bashIni) if ret is not None: # None == success if len(ret) != 1: if len(ret) == 0: msgtext = _( u"Wrye Bash could not find a game to manage. Please use " u"-o command line argument to specify the game path") else: msgtext = _( u"Wrye Bash could not determine which game to manage. " u"The following games have been detected, please select " u"one to manage.") msgtext += u'\n\n' msgtext += _( u'To prevent this message in the future, use the -g ' u'command line argument to specify the game') try: # First try using wxPython # raise BoltError("TEST TINKER") retCode = _wxSelectGame(ret, msgtext) except: # No good with wxPython, use Tkinter instead ##: what use ? retCode = _tinkerSelectGame(ret, msgtext) if retCode is None: return # Add the game to the command line, so we use it if we restart sys.argv = sys.argv + ['-g', retCode] bush.setGame(retCode, opts.oblivionPath, bashIni) else: bush.setGame(ret[0], opts.oblivionPath, bashIni) # from now on bush.game is set if opts.bashmon: # ensure the console is set up properly import ctypes ctypes.windll.kernel32.AllocConsole() sys.stdin = open('CONIN$', 'r') sys.stdout = open('CONOUT$', 'w', 0) sys.stderr = open('CONOUT$', 'w', 0) # run bashmon and exit import bashmon bashmon.monitor(0.25) #--Call monitor with specified sleep interval return #--Initialize Directories and some settings # required before the rest has imported SetUserPath(uArg=opts.userPath) try: # Force Python mode if CBash can't work with this game bolt.CBash = opts.mode if bush.game.esp.canCBash else 1 import bosh isUAC = bosh.testUAC(bush.gamePath.join(u'Data')) bosh.initBosh(opts.personalPath, opts.localAppDataPath, opts.oblivionPath, bashIni) # if HTML file generation was requested, just do it and quit if opts.genHtml is not None: msg1 = _(u"generating HTML file from: '%s'") % opts.genHtml msg2 = _(u'done') try: print msg1 except UnicodeError: print msg1.encode(bolt.Path.sys_fs_enc) import belt bolt.WryeText.genHtml(opts.genHtml) try: print msg2 except UnicodeError: print msg2.encode(bolt.Path.sys_fs_enc) return global basher, balt, barb import basher import barb import balt except (bolt.PermissionError, bolt.BoltError) as e: _showErrorInGui(e) return # not actually needed as _showErrorInGui will re-raise e if not oneInstanceChecker(): return atexit.register(exit) basher.InitSettings() basher.InitLinks() basher.InitImages() #--Start application if opts.debug: if hasattr(sys, 'frozen'): # Special case for py2exe version app = basher.BashApp() # Regain control of stdout/stderr from wxPython sys.stdout = old_stderr sys.stderr = old_stderr else: app = basher.BashApp(False) else: app = basher.BashApp() if not hasattr(sys, 'frozen') and (not _rightWxVersion() or not _rightPythonVersion()): return # process backup/restore options # quit if either is true, but only after calling both quit_ = cmdBackup() quit_ = cmdRestore() or quit_ if quit_: return basher.isUAC = isUAC if isUAC: uacRestart = False if not opts.noUac and not opts.uac: # Show a prompt asking if we should restart in Admin Mode message = _( u"Wrye Bash needs Administrator Privileges to make changes " u"to the %(gameName)s directory. If you do not start Wrye " u"Bash with elevated privileges, you will be prompted at " u"each operation that requires elevated privileges.") % { 'gameName': bush.game.displayName } title = _(u'UAC Protection') if balt.canVista: admin = _(u'Run with Administrator Privileges') readme = bosh.dirs['mopy'].join( u'Docs', u'Wrye Bash General ' u'Readme.html') if readme.exists(): readme = u'file:///'+readme.s.replace(u'\\',u'/').\ replace(u' ',u'%20') else: # Fallback to SVN repository readme = u"http://wrye-bash.github.io/docs/Wrye%20Bash" \ u"%20General%20Readme.html" readme += '#trouble-permissions' uacRestart = balt.vistaDialog( None, message=message, buttons=[ (True, u'+' + admin), (False, _(u'Run normally')), ], title=title, expander=[ _(u'How to avoid this message in the future'), _(u'Less information'), (_(u'Use one of the following command line switches:') + u'\n\n' + _(u'--no-uac: always run normally') + u'\n' + _(u'--uac: always run with Admin Privileges') + u'\n\n' + _(u'See the <A href="%(readmePath)s">readme</A> ' u'for more information.') % { 'readmePath': readme }) ], ) else: uacRestart = balt.askYes( None, message + u'\n\n' + _(u'Start Wrye Bash with Administrator Privileges?'), title) elif opts.uac: uacRestart = True if uacRestart: basher.appRestart = True basher.uacRestart = True return frame = app.Init() # Link.Frame is set here ! frame.booting = False app.MainLoop()
def _main(opts): """Run the Wrye Bash main loop. This function is marked private because it should be inside a try-except block. Call main() from the outside. :param opts: command line arguments """ import barg bass.sys_argv = barg.convert_to_long_options(sys.argv) import env # env imports bolt (this needs fixing) bolt.deprintOn = opts.debug # useful for understanding context of bug reports if opts.debug or is_standalone: # Standalone stdout is NUL no matter what. Redirect it to stderr. # Also, setup stdout/stderr to the debug log if debug mode / # standalone before wxPython is up global _bugdump_handle # _bugdump_handle = io.open(os.path.join(os.getcwdu(),u'BashBugDump.log'),'w',encoding='utf-8') _bugdump_handle = codecs.getwriter('utf-8')(open( os.path.join(os.getcwdu(), u'BashBugDump.log'), 'w')) sys.stdout = _bugdump_handle sys.stderr = _bugdump_handle old_stderr = _bugdump_handle if opts.debug: dump_environment() # Check if there are other instances of Wrye Bash running instance = _wx.SingleInstanceChecker('Wrye Bash') # must stay alive ! assure_single_instance(instance) global initialization import initialization #--Bash installation directories, set on boot, not likely to change initialization.init_dirs_mopy_and_cd(is_standalone) # if HTML file generation was requested, just do it and quit if opts.genHtml is not None: msg1 = _(u"generating HTML file from: '%s'") % opts.genHtml msg2 = _(u'done') try: print msg1 except UnicodeError: print msg1.encode(bolt.Path.sys_fs_enc) import belt # this imports bosh which imports wx (DUH) bolt.WryeText.genHtml(opts.genHtml) try: print msg2 except UnicodeError: print msg2.encode(bolt.Path.sys_fs_enc) return # We need the Mopy dirs to initialize restore settings instance bash_ini_path, restore_ = u'bash.ini', None # import barb that does not import from bosh/balt/bush import barb if opts.restore: try: restore_ = barb.RestoreSettings(opts.filename) restore_.extract_backup() # get the bash.ini from the backup, or None - use in _detect_game bash_ini_path = restore_.backup_ini_path() except (exception.BoltError, exception.StateError, OSError, IOError): bolt.deprint(u'Failed to restore backup', traceback=True) restore_ = None # The rest of backup/restore functionality depends on setting the game try: bashIni, bush_game, game_ini_path = _detect_game(opts, bash_ini_path) if not bush_game: return if restore_: try: # TODO(ut) error checks - limit except Exception below restore_.restore_settings(bush_game.fsName) # we currently disallow backup and restore on the same boot if opts.quietquit: return except Exception: bolt.deprint(u'Failed to restore backup', traceback=True) restore_.restore_ini() # reset the game and ini import bush bush.reset_bush_globals() bashIni, bush_game, game_ini_path = _detect_game( opts, u'bash.ini') import bosh # this imports balt (DUH) which imports wx bosh.initBosh(bashIni, game_ini_path) env.isUAC = env.testUAC(bush_game.gamePath.join(u'Data')) global basher, balt import basher, balt except (exception.PermissionError, exception.BoltError, ImportError, OSError, IOError) as e: msg = u'\n'.join([ _(u'Error! Unable to start Wrye Bash.'), u'\n', _(u'Please ensure Wrye Bash is correctly installed.'), u'\n', traceback.format_exc(e) ]) _close_dialog_windows() _show_wx_error(msg) return atexit.register(exit_cleanup) basher.InitSettings() basher.InitLinks() basher.InitImages() #--Start application if opts.debug: if is_standalone: # Special case for py2exe version app = basher.BashApp() # Regain control of stdout/stderr from wxPython sys.stdout = old_stderr sys.stderr = old_stderr else: app = basher.BashApp(False) else: app = basher.BashApp() if not is_standalone and (not _rightWxVersion() or not _rightPythonVersion()): return if env.isUAC: uacRestart = opts.uac if not opts.noUac and not opts.uac: # Show a prompt asking if we should restart in Admin Mode message = _( u"Wrye Bash needs Administrator Privileges to make changes " u"to the %(gameName)s directory. If you do not start Wrye " u"Bash with elevated privileges, you will be prompted at " u"each operation that requires elevated privileges.") % { 'gameName': bush_game.displayName } uacRestart = balt.ask_uac_restart(message, title=_(u'UAC Protection'), mopy=bass.dirs['mopy']) if uacRestart: bass.update_sys_argv(['--uac']) if uacRestart: bass.is_restarting = True return # Backup the Bash settings - we need settings being initialized to get # the previous version - we should read this from a file so we can move # backup higher up in the boot sequence. previous_bash_version = bass.settings['bash.version'] # backup settings if app version has changed or on user request if opts.backup or barb.BackupSettings.new_bash_version_prompt_backup( balt, previous_bash_version): frame = None # balt.Link.Frame, not defined yet, no harm done base_dir = bass.settings['bash.backupPath'] or bass.dirs['modsBash'] settings_file = (opts.backup and opts.filename) or None if not settings_file: settings_file = balt.askSave( frame, title=_(u'Backup Bash Settings'), defaultDir=base_dir, wildcard=u'*.7z', defaultFile=barb.BackupSettings.backup_filename( bush_game.fsName)) if settings_file: with balt.BusyCursor(): backup = barb.BackupSettings(settings_file, bush_game.fsName) try: with balt.BusyCursor(): backup.backup_settings(balt) except exception.StateError: if balt.askYes( frame, u'\n'.join([ _(u'There was an error while trying to backup the ' u'Bash settings!'), _(u'If you continue, your current settings may be ' u'overwritten.'), _(u'Do you want to quit Wrye Bash now?') ]), title=_(u'Unable to create backup!')): return # Quit app.Init() # Link.Frame is set here ! app.MainLoop()