Source code for core.baselines

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Advanced raw and data folder management, for mods or graphics packs."""

import fnmatch
import glob
import os
import shutil
import tarfile
import zipfile

from . import log, paths, update
from .lnp import lnp

[docs]def find_vanilla(download_missing=True): """Finds the vanilla baseline for the current version. Starts by unzipping any DF releases in baselines and preprocessing them. If download_missing is set to True, missing baselines will be downloaded. Returns: Path to the vanilla folder, eg ``'LNP/Baselines/df_40_15'``, ``False`` if baseline not available (and start download), ``None`` if version detection is not accurate """ if lnp.df_info.source == "init detection": log.w('Baseline DF version from init detection; highly unreliable!') return None prepare_baselines() version = 'df_' + str(lnp.df_info.version)[2:].replace('.', '_') if os.path.isdir(paths.get('baselines', version)): return paths.get('baselines', version) if download_missing: update.download_df_baseline() return False
[docs]def find_vanilla_raws(download_missing=True): """Finds vanilla raws for the current version.""" retval = find_vanilla(download_missing) if retval: return os.path.join(retval, 'raw') return retval
[docs]def prepare_baselines(): """Unzip any DF releases found, and discard non-universal files.""" archives = glob.glob(os.path.join(paths.get('baselines'), 'df_??_?*.???')) if archives: log.i('Extracting archives in baselines: ' + str(archives)) for item in archives: version = os.path.basename(item) for s in ('_win32', '_osx32', '_linux32', '_legacy32', '_win', '_osx', '_linux', '_legacy', '_s', '.zip', '.tar.bz2'): version = version.replace(s, '') f = paths.get('baselines', version) if not os.path.isdir(f): if item.endswith('.zip'): with zipfile.ZipFile(item) as zipped: zipped.extractall(f) elif item.endswith('.tar.bz2'): with tarfile.TarFile(item) as tarred: tarred.extractall(f) for k in glob.glob(os.path.join(f, 'df_*x', '*')): shutil.move(k, f) simplify_pack(version, 'baselines') os.remove(item)
[docs]def set_auto_download(value): """Sets the option for auto-download of baselines.""" lnp.userconfig['downloadBaselines'] = value lnp.userconfig.save_data()
[docs]def simplify_pack(pack, folder): """Removes unnecessary files from LNP/<folder>/<pack>. Args: pack, folder: path segments in ``'./LNP/folder/pack/'`` as strings Returns: The number of files removed if successful, ``False`` if an exception occurred, ``None`` if folder is empty """ if folder not in ('graphics', 'mods', 'baselines'): return False log.i('Simplifying {}: {}'.format(folder, pack)) packdir = paths.get(folder, pack) files_before = sum(len(f) for _, _, f in os.walk(packdir)) if files_before == 0: return None keep = [('raw',), ('data', 'speech')] if folder == 'graphics': keep = [('raw', 'objects'), ('raw', 'graphics')] if folder != 'mods': keep += [('data', 'art')] + [ ('data', 'init', f + '.txt') for f in ('colors', 'd_init', 'init', 'overrides')] if folder == 'baselines': keep.append(('data', 'init', 'interface.txt')) keep = [os.path.join(*k) for k in keep] for root, _, files in os.walk(packdir): for k in files: if k == 'manifest.json' or 'readme' in k.lower(): continue f = os.path.join(root, k) if not any(fnmatch.fnmatch(f, os.path.join(packdir, pattern, '*')) for pattern in keep): os.remove(f) files_after = sum(len(f) for _, _, f in os.walk(packdir)) log.v('Removed {} files'.format(files_before - files_after)) return files_before - files_after
[docs]def remove_vanilla_raws_from_pack(pack, folder): """Remove files identical to vanilla raws, return files removed Args: pack, folder: path segments in ``'./LNP/folder/pack/'`` as strings Returns: int: the number of files removed """ if not find_vanilla(): return 0 i = 0 for _folder, van_folder in ( [paths.get(folder, pack, 'raw'), find_vanilla_raws()], [paths.get(folder, pack, 'data', 'speech'), os.path.join(find_vanilla(), 'data', 'speech')]): for root, _, files in os.walk(_folder): for k in files: f = os.path.join(root, k) silently_kill = ('Thumbs.db', 'installed_raws.txt') if any(f.endswith(x) for x in silently_kill): os.remove(f) continue van_f = os.path.join(van_folder, os.path.relpath(f, _folder)) if os.path.isfile(van_f): with open(van_f, encoding='cp437', errors='replace') as v: vtext = with open(f, encoding='cp437', errors='replace') as m: mtext = if vtext == mtext: os.remove(f) i += 1 return i
[docs]def remove_empty_dirs(pack, folder): """Removes empty subdirs in a mods or graphics pack. Args: pack, folder: path segments in ``'./LNP/folder/pack/'`` as strings Returns: int: the number of dirs removed """ i = 0 for _ in range(3): # only catches the lowest level each iteration for root, dirs, files in os.walk(paths.get(folder, pack)): if not dirs and not files: os.rmdir(root) i += 1 return i