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)
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)
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]
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
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()
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
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
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
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
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
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
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