""" Provides functionality for loading and resetting the package settings. author: Michael Grupp This file is part of evo (github.com/MichaelGrupp/evo). evo is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. evo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with evo. If not, see <http://www.gnu.org/licenses/>. """ from __future__ import print_function import os import json import logging from colorama import Fore from evo import EvoException logger = logging.getLogger(__name__) PACKAGE_BASE_PATH = os.path.abspath(__file__ + "/../../") PACKAGE_VERSION = open(os.path.join(PACKAGE_BASE_PATH, "version")).read() USER_ASSETS_PATH = os.path.join(os.path.expanduser('~'), ".evo") USER_ASSETS_VERSION_PATH = os.path.join(USER_ASSETS_PATH, "assets_version") DEFAULT_PATH = os.path.join(USER_ASSETS_PATH, "settings.json") GLOBAL_LOGFILE_PATH = os.path.join(USER_ASSETS_PATH, "evo.log") class SettingsException(EvoException): pass class SettingsContainer(dict): def __init__(self, data, lock=True): super(SettingsContainer, self).__init__() for k, v in data.items(): setattr(self, k, v) setattr(self, "__locked__", lock) @classmethod def from_json_file(cls, settings_path): with open(settings_path) as settings_file: data = json.load(settings_file) return SettingsContainer(data) def locked(self): if "__locked__" in self: return self["__locked__"] def __getattr__(self, attr): # allow dot access if attr not in self: raise SettingsException("unknown settings parameter: " + str(attr)) return self[attr] def __setattr__(self, attr, value): # allow dot access if self.locked() and attr not in self: raise SettingsException( "write-access locked, can't add new parameter {}".format(attr)) else: self[attr] = value def merge_dicts(first, second, soft=False): if soft: first.update({k: v for k, v in second.items() if k not in first}) else: first.update(second) return first def write_to_json_file(json_path, dictionary): with open(json_path, 'w') as json_file: json_file.write(json.dumps(dictionary, indent=4, sort_keys=True)) def reset(dest=DEFAULT_PATH): from evo.tools.settings_template import DEFAULT_SETTINGS_DICT write_to_json_file(dest, DEFAULT_SETTINGS_DICT) def initialize_if_needed(): """ Initialize evo user folder after first installation (or if it was deleted). """ if not os.path.isdir(USER_ASSETS_PATH): os.makedirs(USER_ASSETS_PATH) if not os.path.exists(USER_ASSETS_VERSION_PATH): open(USER_ASSETS_VERSION_PATH, 'w').write(PACKAGE_VERSION) if not os.path.exists(DEFAULT_PATH): try: reset(dest=DEFAULT_PATH) print("{}Initialized new {}{}".format(Fore.LIGHTYELLOW_EX, DEFAULT_PATH, Fore.RESET)) except: logger.error("Fatal: failed to write package settings file {}". format(DEFAULT_PATH)) raise def update_if_outdated(): """ Update user settings to a new version if needed. """ if open(USER_ASSETS_VERSION_PATH).read() == PACKAGE_VERSION: return from evo.tools.settings_template import DEFAULT_SETTINGS_DICT old_settings = json.loads(open(DEFAULT_PATH).read()) updated_settings = merge_dicts(old_settings, DEFAULT_SETTINGS_DICT, soft=True) write_to_json_file(DEFAULT_PATH, updated_settings) open(USER_ASSETS_VERSION_PATH, 'w').write(PACKAGE_VERSION) print("{}Updated outdated {}{}".format(Fore.LIGHTYELLOW_EX, DEFAULT_PATH, Fore.RESET)) # Load the user settings into this container. initialize_if_needed() update_if_outdated() SETTINGS = SettingsContainer.from_json_file(DEFAULT_PATH)