Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
            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()
Ejemplo n.º 3
0
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()
Ejemplo n.º 4
0
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()