Beispiel #1
0
 def restore_settings(self, fsName):
     if self._bash_ini_path is self.__unset:
         raise BoltError(
             u'restore_settings: you must handle bash ini first')
     if self._extract_dir is self.__unset:
         raise BoltError(
             u'restore_settings: you must extract the settings file first')
     try:
         self._restore_settings(fsName)
     finally:
         self.remove_extract_dir(self._extract_dir)
Beispiel #2
0
 def _get_backup_game(self):
     """Get the game this backup was for - hack, this info belongs to backup.dat."""
     for node in os.listdir(u'%s' % self._extract_dir):
         if node != u'My Games' and not node.endswith(
                 u'Mods') and os.path.isdir(self._extract_dir.join(node).s):
             return node
     raise BoltError(u'%s does not contain a game dir' % self._extract_dir)
Beispiel #3
0
 def subEnv(match):
     key = match.group(1).upper()
     if not envDefs.get(key):
         raise BoltError(
             u'Can\'t find user directories in windows registry'
             u'.\n>> See "If Bash Won\'t Start" in bash docs for help.')
     return envDefs[key]
Beispiel #4
0
def _init_settings_files(fsName_):
    """Construct a dict mapping directory paths to setting files. Keys are
    tuples of absolute paths to directories, paired with the relative paths
    in the backup file. Values are sets of setting files in those paths,
    or empty, meaning we have to list those paths and backup everything."""
    if not initialization.bash_dirs_initialized:
        raise BoltError(u'_init_settings_files: Bash dirs are not initialized')
    settings_info = {
        (dirs['mopy'], jo(fsName_, u'Mopy')): {
            u'bash.ini',
        },
        (dirs['mods'].join(u'Bash'), jo(fsName_, u'Data', u'Bash')): {
            u'Table.dat',
        },
        (dirs['mods'].join(u'Docs'), jo(fsName_, u'Data', u'Docs')): {
            u'Bash Readme Template.txt',
            u'Bash Readme Template.html',
            u'My Readme Template.txt',
            u'My Readme Template.html',
            u'wtxt_sand_small.css',
            u'wtxt_teal.css',
        },
        (dirs['modsBash'], jo(fsName_ + u' Mods', u'Bash Mod Data')): {
            u'Table.dat',
        },
        (dirs['modsBash'].join(u'INI Data'),
         jo(fsName_ + u' Mods', u'Bash Mod Data', u'INI Data')): {
            u'Table.dat',
        },
        (dirs['bainData'], jo(fsName_ + u' Mods', u'Bash Installers', u'Bash')):
        {
            u'Converters.dat',
            u'Installers.dat',
        },
        (dirs['saveBase'], jo(u'My Games', fsName_)): {
            u'BashProfiles.dat',
            u'BashSettings.dat',
            u'BashLoadOrders.dat',
            u'People.dat',
        },
        # backup all files in Mopy\bash\l10n, Data\Bash Patches\ and
        # Data\INI Tweaks\
        (dirs['l10n'], jo(fsName_, u'Mopy', u'bash', u'l10n')): {},
        (dirs['mods'].join(u'Bash Patches'),
         jo(fsName_, u'Data', u'Bash Patches')): {},
        (dirs['mods'].join(u'INI Tweaks'), jo(fsName_, u'Data', u'INI Tweaks')):
        {},
    }
    for setting_files in settings_info.itervalues():
        for settings_file in set(setting_files):
            if settings_file.endswith(u'.dat'):  # add corresponding bak file
                setting_files.add(settings_file + u'.bak')
    return settings_info
Beispiel #5
0
def __setGame(name, msg):
    """Set bush game globals - raise if they are already set."""
    global game, game_mod
    if game is not None: raise BoltError(u'Trying to reset the game')
    gamePath = foundGames[name]
    game = _allGames[name](gamePath)
    game_mod = _allModules[name]
    deprint(msg % {'gamename': name}, gamePath)
    # Unload the other modules from the cache
    for i in _allGames.keys():
        if i != name:
            del _allGames[i]
            del _allModules[i]  # the keys should be the same
    game.init()
Beispiel #6
0
 def backup_ini_path(self):
     """Get the path to the backup bash.ini if it exists - must be run
     before restore_settings is called, as we need the Bash ini to
     initialize bass.dirs."""
     if self._extract_dir is self.__unset:
         raise BoltError(
             u'backup_ini_path: you must extract the settings file first')
     for r, d, fs in bolt.walkdir(u'%s' % self._extract_dir):
         for f in fs:
             if f == u'bash.ini':
                 self._bash_ini_path = jo(r, f)
                 break
     else:
         self.bash_ini_path = None
     return self._bash_ini_path
Beispiel #7
0
 def extract_backup(self):
     """Extract the backup file and return the tmp directory used. If
     the backup file is a dir we assume it was created by us before
     restarting."""
     if self._settings_file.isfile():
         temp_dir = bolt.Path.tempDir(
             prefix=RestoreSettings.__tmpdir_prefix)
         archives.extract7z(self._settings_file, temp_dir)
         self._extract_dir = temp_dir
     elif self._settings_file.isdir():
         self._extract_dir = self._settings_file
     else:
         raise BoltError(u'%s is not a valid backup location' %
                         self._settings_file)
     return self._extract_dir
Beispiel #8
0
 def _get_settings_versions(self):
     if self._extract_dir is self.__unset:
         raise BoltError(
             u'_get_settings_versions: you must extract the settings file '
             u'first')
     if self._saved_settings_version is None:
         backup_dat = self._extract_dir.join(u'backup.dat')
         try:
             with backup_dat.open('rb') as ins:
                 # version of Bash that created the backed up settings
                 self._saved_settings_version = cPickle.load(ins)
                 # version of Bash that created the backup
                 self._settings_saved_with = cPickle.load(ins)
         except (OSError, IOError, cPickle.UnpicklingError, EOFError):
             raise_bolt_error(u'Failed to read %s' % backup_dat)
     return self._saved_settings_version, self._settings_saved_with
Beispiel #9
0
 def _getShellPath(folderKey):  ##: mkdirs
     if not winreg:  # Linux HACK
         home = _os.path.expanduser("~")
         return {
             'Personal': home,
             'Local AppData': home + u'/.local/share'
         }[folderKey]
     regKey = winreg.OpenKey(
         winreg.HKEY_CURRENT_USER,
         r'Software\Microsoft\Windows\CurrentVersion'
         r'\Explorer\User Shell Folders')
     try:
         path = winreg.QueryValueEx(regKey, folderKey)[0]
     except WindowsError:
         raise BoltError(
             u'Can\'t find user directories in windows registry'
             u'.\n>> See "If Bash Won\'t Start" in bash docs for help.')
     regKey.Close()
     path = reEnv.sub(subEnv, path)
     return path
Beispiel #10
0
def getPersonalPath(bash_ini_, my_docs_path):
    #--Determine User folders from Personal and Local Application Data directories
    #  Attempt to pull from, in order: Command Line, Ini, win32com, Registry
    if my_docs_path:
        my_docs_path = GPath(my_docs_path)
        sErrorInfo = _(u"Folder path specified on command line (-p)")
    else:
        my_docs_path = get_path_from_ini(bash_ini_, 'sPersonalPath')
        if my_docs_path:
            sErrorInfo = _(
                u"Folder path specified in bash.ini (%s)") % u'sPersonalPath'
        else:
            my_docs_path, sErrorInfo = get_personal_path()
    #  If path is relative, make absolute
    if not my_docs_path.isabs():
        my_docs_path = dirs['app'].join(my_docs_path)
    #  Error check
    if not my_docs_path.exists():
        raise BoltError(u"Personal folder does not exist.\n"
                        u"Personal folder: %s\nAdditional info:\n%s" %
                        (my_docs_path.s, sErrorInfo))
    return my_docs_path
Beispiel #11
0
def _detectGames(cli_path=u'', bash_ini_=None):
    """Detect which supported games are installed.

    - If Bash supports no games raise.
    - For each game supported by Bash check for a supported game executable
    in the following dirs, in decreasing precedence:
       - the path provided by the -o cli argument if any
       - the sOblivionPath Bash Ini entry if present
       - one directory up from Mopy
    If a game exe is found update the path to this game and return immediately.
    Return (foundGames, name)
      - foundGames: a dict from supported games to their paths (the path will
      default to the windows registry path to the game, if present)
      - name: the game found in the first installDir or None if no game was
      found - a 'suggestion' for a game to use (if no game is specified/found
      via -g argument).
    """
    #--Find all supported games and all games in the windows registry
    foundGames_ = _supportedGames()  # sets _allGames if not set
    if not _allGames:  # if allGames is empty something goes badly wrong
        raise BoltError(_(u'No game support modules found in Mopy/bash/game.'))
    # check in order of precedence the -o argument, the ini and our parent dir
    installPaths = collections.OrderedDict(
    )  #key->(path, found msg, error msg)
    #--First: path specified via the -o command line argument
    if cli_path != u'':
        test_path = GPath(cli_path)
        if not test_path.isabs():
            test_path = Path.getcwd().join(test_path)
        installPaths['cmd'] = (
            test_path,
            _(u'Set game mode to %(gamename)s specified via -o argument') +
            u': ',
            _(u'No known game in the path specified via -o argument: ' +
              u'%(path)s'))
    #--Second: check if sOblivionPath is specified in the ini
    ini_game_path = get_ini_option(bash_ini_, u'sOblivionPath')
    if ini_game_path and not ini_game_path == u'.':
        test_path = GPath(ini_game_path.strip())
        if not test_path.isabs():
            test_path = Path.getcwd().join(test_path)
        installPaths['ini'] = (
            test_path,
            _(u'Set game mode to %(gamename)s based on sOblivionPath setting '
              u'in bash.ini') + u': ',
            _(u'No known game in the path specified in sOblivionPath ini '
              u'setting: %(path)s'))
    #--Third: Detect what game is installed one directory up from Mopy
    test_path = Path.getcwd()
    if test_path.cs[-4:] == u'mopy':
        test_path = GPath(test_path.s[:-5])
        if not test_path.isabs():
            test_path = Path.getcwd().join(test_path)
        installPaths['upMopy'] = (
            test_path,
            _(u'Set game mode to %(gamename)s found in parent directory of'
              u' Mopy') + u': ',
            _(u'No known game in parent directory of Mopy: %(path)s'))
    #--Detect
    deprint(
        u'Detecting games via the -o argument, bash.ini and relative path:')
    # iterate installPaths in insert order ('cmd', 'ini', 'upMopy')
    for test_path, foundMsg, errorMsg in installPaths.itervalues():
        for name, info in _allGames.items():
            if test_path.join(*info.game_detect_file).exists():
                # Must be this game
                deprint(foundMsg % {'gamename': name}, test_path)
                foundGames_[name] = test_path
                return foundGames_, name
        # no game exe in this install path - print error message
        deprint(errorMsg % {'path': test_path.s})
    # no game found in installPaths - foundGames are the ones from the registry
    return foundGames_, None
Beispiel #12
0
def init_dirs(bashIni_, personal, localAppData, game_info):
    if not mopy_dirs_initialized:
        raise BoltError(u'init_dirs: Mopy dirs uninitialized')
    #--Oblivion (Application) Directories
    dirs['app'] = game_info.gamePath
    dirs['defaultPatches'] = dirs['mopy'].join(u'Bash Patches',
                                               game_info.fsName)

    #  Personal
    personal = getPersonalPath(bashIni_, personal)
    dirs['saveBase'] = personal.join(u'My Games', game_info.fsName)

    #  Local Application Data
    localAppData = getLocalAppDataPath(bashIni_, localAppData)
    dirs['userApp'] = localAppData.join(game_info.fsName)

    # Use local copy of the oblivion.ini if present
    # see: http://en.uesp.net/wiki/Oblivion:Ini_Settings
    # Oblivion reads the Oblivion.ini in the directory where it exists
    # first, and only if bUseMyGames is non-existent or set to 1 does it
    # then look for My Documents\My Games\Oblivion.ini. In other words,
    # both can exist simultaneously, and only the value of bUseMyGames in
    # the Oblivion.ini directory where Oblivion.exe is run from will
    # actually matter.
    # Utumno: not sure how/if this applies to other games
    data_oblivion_ini = dirs['app'].join(game_info.iniFiles[0])
    game_ini_path = dirs['saveBase'].join(game_info.iniFiles[0])
    dirs['mods'] = dirs['app'].join(u'Data')
    if data_oblivion_ini.exists():
        oblivionIni = ConfigParser()
        oblivionIni.read(data_oblivion_ini.s)
        # is bUseMyGamesDirectory set to 0?
        if get_ini_option(oblivionIni, u'bUseMyGamesDirectory') == u'0':
            game_ini_path = data_oblivion_ini
            # Set the save game folder to the Oblivion directory
            dirs['saveBase'] = dirs['app']
            # Set the data folder to sLocalMasterPath
            dirs['mods'] = dirs['app'].join(
                get_ini_option(oblivionIni, u'SLocalMasterPath') or u'Data')
    # these are relative to the mods path so they must be set here
    dirs['patches'] = dirs['mods'].join(u'Bash Patches')
    dirs['tweaks'] = dirs['mods'].join(u'INI Tweaks')
    #--Mod Data, Installers
    oblivionMods, oblivionModsSrc = getOblivionModsPath(bashIni_, game_info)
    dirs['modsBash'], modsBashSrc = getBashModDataPath(bashIni_, game_info)
    dirs['modsBash'], modsBashSrc = getLegacyPathWithSource(
        dirs['modsBash'], dirs['app'].join(u'Data', u'Bash'), modsBashSrc,
        u'Relative Path')

    dirs['installers'] = oblivionMods.join(u'Bash Installers')
    dirs['installers'] = getLegacyPath(dirs['installers'],
                                       dirs['app'].join(u'Installers'))

    dirs['bainData'], bainDataSrc = getBainDataPath(bashIni_)

    dirs['bsaCache'] = dirs['bainData'].join(u'BSA Cache')

    dirs['converters'] = dirs['installers'].join(u'Bain Converters')
    dirs['dupeBCFs'] = dirs['converters'].join(u'--Duplicates')
    dirs['corruptBCFs'] = dirs['converters'].join(u'--Corrupt')

    # create bash user folders, keep these in order
    keys = ('modsBash', 'installers', 'converters', 'dupeBCFs', 'corruptBCFs',
            'bainData', 'bsaCache')
    try:
        env.shellMakeDirs([dirs[key] for key in keys])
    except NonExistentDriveError as e:
        # NonExistentDriveError is thrown by shellMakeDirs if any of the
        # directories cannot be created due to residing on a non-existing
        # drive. Find which keys are causing the errors
        badKeys = set()  # List of dirs[key] items that are invalid
        # First, determine which dirs[key] items are causing it
        for key in keys:
            if dirs[key] in e.failed_paths:
                badKeys.add(key)
        # Now, work back from those to determine which setting created those
        msg = _(u'Error creating required Wrye Bash directories.') + u'  ' + _(
            u'Please check the settings for the following paths in your '
            u'bash.ini, the drive does not exist') + u':\n\n'
        relativePathError = []
        if 'modsBash' in badKeys:
            if isinstance(modsBashSrc, list):
                msg += (u' '.join(modsBashSrc) + u'\n    ' +
                        dirs['modsBash'].s + u'\n')
            else:
                relativePathError.append(dirs['modsBash'])
        if {'installers', 'converters', 'dupeBCFs', 'corruptBCFs'} & badKeys:
            # All derived from oblivionMods -> getOblivionModsPath
            if isinstance(oblivionModsSrc, list):
                msg += (u' '.join(oblivionModsSrc) + u'\n    ' +
                        oblivionMods.s + u'\n')
            else:
                relativePathError.append(oblivionMods)
        if {'bainData', 'bsaCache'} & badKeys:
            # Both derived from 'bainData' -> getBainDataPath
            # Sometimes however, getBainDataPath falls back to oblivionMods,
            # So check to be sure we haven't already added a message about that
            if bainDataSrc != oblivionModsSrc:
                if isinstance(bainDataSrc, list):
                    msg += (u' '.join(bainDataSrc) + u'\n    ' +
                            dirs['bainData'].s + u'\n')
                else:
                    relativePathError.append(dirs['bainData'])
        if relativePathError:
            msg += u'\n' + _(u'A path error was the result of relative paths.')
            msg += u'  ' + _(
                u'The following paths are causing the errors, '
                u'however usually a relative path should be fine.')
            msg += u'  ' + _(u'Check your setup to see if you are using '
                             u'symbolic links or NTFS Junctions') + u':\n\n'
            msg += u'\n'.join([u'%s' % x for x in relativePathError])
        raise BoltError(msg)
    global bash_dirs_initialized
    bash_dirs_initialized = True
    return game_ini_path