forked from bartvdbraak/blender
255 lines
7.2 KiB
Python
255 lines
7.2 KiB
Python
# --------------------------------------------------------------------------
|
|
# Module BPyRegistry version 0.1
|
|
# Helper functions to store / restore configuration data.
|
|
# --------------------------------------------------------------------------
|
|
# $Id$
|
|
#
|
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
|
#
|
|
# Copyright (C) 2004: Willian P. Germano, wgermano _at_ ig.com.br
|
|
#
|
|
# This program 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 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program 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 this program; if not, write to the Free Software Foundation,
|
|
# --------------------------------------------------------------------------
|
|
|
|
# The Registry is a Python dictionary that is kept in Blender for as long as
|
|
# the program is running, where scripts can store / restore persistent data
|
|
# (data that is not lost when the script exits). This module provides
|
|
# functions to save and restore Registry entries as config data in the
|
|
# bpydata/config folder. Scripts just need to give an extra parameter to
|
|
# the Blender.Registry.Get/Set() functions to have their data automatically
|
|
# saved and restored when needed.
|
|
#
|
|
# Note: entries starting with an underscore are not saved, so script authors
|
|
# can use that fact to define data that is not meant to be stored in a
|
|
# config file. Example: data to be passed to another script and references to
|
|
# invalid data, like Blender objects and any function or method.
|
|
#
|
|
# Check the Blender.Registry documentation for more information.
|
|
|
|
import Blender
|
|
from Blender import Registry, sys as bsys
|
|
|
|
_EXT = '.cfg' # file extension for saved config data
|
|
|
|
# limits:
|
|
MAX_ITEMS_NUM = 60 # max number of keys per dict and itens per list and tuple
|
|
MAX_STR_LEN = 300 # max string length (remember this is just for config data)
|
|
|
|
_CFG_DIR = ''
|
|
if Blender.Get('udatadir'):
|
|
_CFG_DIR = Blender.sys.join(Blender.Get('udatadir'), 'config')
|
|
if not _CFG_DIR or not bsys.exists(_CFG_DIR):
|
|
_CFG_DIR = Blender.sys.join(Blender.Get('datadir'), 'config')
|
|
if not bsys.exists(_CFG_DIR):
|
|
_CFG_DIR = ''
|
|
|
|
# to compare against, so we don't write to a cvs tree:
|
|
_CVS_SUBPATH = 'release/scripts/bpydata/config/'
|
|
if bsys.dirsep == '\\':
|
|
_CVS_SUBPATH = _CVS_SUBPATH.replace('/', '\\')
|
|
|
|
_KEYS = [k for k in Registry.Keys() if k[0] != '_']
|
|
|
|
_ITEMS_NUM = 0
|
|
|
|
def _sanitize(o):
|
|
"Check recursively that all objects are valid, set invalid ones to None"
|
|
|
|
global MAX_ITEMS_NUM, MAX_STR_LEN, _ITEMS_NUM
|
|
|
|
valid_types = [int, float, bool, long, type]
|
|
valid_checked_types = [str, unicode]
|
|
# Only very simple types are considered valid for configuration data,
|
|
# functions, methods and Blender objects (use their names instead) aren't.
|
|
|
|
t = type(o)
|
|
|
|
if t == dict:
|
|
keys = o.keys()
|
|
len_keys = len(keys)
|
|
_ITEMS_NUM += len_keys
|
|
if _ITEMS_NUM > MAX_ITEMS_NUM:
|
|
return None
|
|
for k in keys:
|
|
o[k] = _sanitize(o[k])
|
|
elif t in [list, tuple]:
|
|
len_seq = len(o)
|
|
_ITEMS_NUM += len_seq
|
|
if _ITEMS_NUM > MAX_ITEMS_NUM:
|
|
return None
|
|
result = []
|
|
for i in o: result.append(_sanitize(i))
|
|
return result
|
|
elif t in valid_types:
|
|
return o
|
|
elif t in valid_checked_types:
|
|
if len(o) > MAX_STR_LEN:
|
|
o = o[:MAX_STR_LEN]
|
|
return o
|
|
else: return None
|
|
|
|
return o
|
|
|
|
|
|
def _dict_to_str(name, d):
|
|
"Return a pretty-print version of the passed dictionary"
|
|
|
|
if name: l = ['%s = {' % name]
|
|
else: l = ['{']
|
|
keys = d.keys()
|
|
for k in keys:
|
|
if type(d[k]) == dict:
|
|
l.append("'%s': %s" % (k, _dict_to_str(None, d[k])))
|
|
else:
|
|
l.append("'%s': %s," % (k, repr(d[k])))
|
|
if name: l.append('}')
|
|
else: l.append('},')
|
|
return "\n".join(l)
|
|
|
|
_HELP_MSG = """
|
|
Please create a valid scripts config dir tree either by
|
|
copying release/scripts/ tree to your <blenderhome> dir
|
|
or by copying release/scripts/bpydata/ tree to a user
|
|
defined scripts dir that you can set in the
|
|
User Preferences -> Paths tab -> Python path input box.
|
|
"""
|
|
|
|
def _check_dir():
|
|
global _CFG_DIR, _CVS_SUBPATH, _HELP_MSG
|
|
|
|
if not _CFG_DIR:
|
|
errmsg = "scripts config dir not found!\n%s" % _HELP_MSG
|
|
raise IOError, errmsg
|
|
elif _CFG_DIR.find(_CVS_SUBPATH) > 0:
|
|
errmsg = """
|
|
Your scripts config dir:\n%s
|
|
seems to reside in your local Blender's cvs tree.\n%s""" % (_CFG_DIR, _HELP_MSG)
|
|
raise SystemError, errmsg
|
|
else: return
|
|
|
|
|
|
# API:
|
|
|
|
BPY_KEY_MISSING = 0
|
|
BPY_KEY_IN_REGISTRY = 1
|
|
BPY_KEY_IN_FILE = 2
|
|
|
|
def HasConfigData (key):
|
|
"""
|
|
Check if the given key exists, either already loaded in the Registry dict or
|
|
as a file in the script data config dir.
|
|
@type key: string
|
|
@param key: a given key name.
|
|
@returns:
|
|
- 0: key does not exist;
|
|
- 1: key exists in the Registry dict only;
|
|
- 2: key exists as a file only;
|
|
- 3: key exists in the Registry dict and also as a file.
|
|
@note: for readability it's better to check against the constant bitmasks
|
|
BPY_KEY_MISSING = 0, BPY_KEY_IN_REGISTRY = 1 and BPY_KEY_IN_FILE = 2.
|
|
"""
|
|
|
|
fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT))
|
|
|
|
result = BPY_KEY_MISSING
|
|
if key in Registry.Keys(): result |= BPY_KEY_IN_REGISTRY
|
|
if bsys.exists(fname): result |= BPY_KEY_IN_FILE
|
|
|
|
return result
|
|
|
|
|
|
def LoadConfigData (key = None):
|
|
"""
|
|
Load config data from file(s) to the Registry dictionary.
|
|
@type key: string
|
|
@param key: a given key name. If None (default), all available keys are
|
|
loaded.
|
|
@returns: None
|
|
"""
|
|
|
|
_check_dir()
|
|
|
|
import os
|
|
|
|
if not key:
|
|
files = \
|
|
[bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f[-4:] == _EXT]
|
|
else:
|
|
files = []
|
|
fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT))
|
|
if bsys.exists(fname): files.append(fname)
|
|
|
|
for p in files:
|
|
f = file(p, 'r')
|
|
lines = f.readlines()
|
|
f.close()
|
|
mainkey = lines[0].split('=')[0].strip()
|
|
pysrc = "\n".join(lines)
|
|
exec(pysrc)
|
|
exec("Registry.SetKey('%s', %s)" % (str(mainkey), mainkey))
|
|
|
|
|
|
def RemoveConfigData (key = None):
|
|
"""
|
|
Remove this key's config file from the <(u)datadir>/config/ folder.
|
|
@type key: string
|
|
@param key: the name of the key to be removed. If None (default) all
|
|
available config files are deleted.
|
|
"""
|
|
|
|
_check_dir()
|
|
|
|
if not key:
|
|
files = \
|
|
[bsys.join(_CFG_DIR, f) for f in os.listdir(_CFG_DIR) if f[-4:] == _EXT]
|
|
else:
|
|
files = []
|
|
fname = bsys.join(_CFG_DIR, "%s%s" % (key, _EXT))
|
|
if bsys.exists(fname): files.append(fname)
|
|
|
|
import os
|
|
|
|
for p in files:
|
|
os.remove(p) # remove the file(s)
|
|
|
|
|
|
def SaveConfigData (key = None):
|
|
"""
|
|
Save Registry key(s) as file(s) in the <(u)datadir>/config/ folder.
|
|
@type key: string
|
|
@param key: the name of the key to be saved. If None (default) all
|
|
available keys are saved.
|
|
"""
|
|
|
|
global _KEYS, _CFG_DIR
|
|
|
|
_check_dir()
|
|
|
|
if key: keys = [key]
|
|
else: keys = _KEYS
|
|
|
|
for mainkey in keys:
|
|
cfgdict = Registry.GetKey(mainkey).copy()
|
|
for k in cfgdict.keys():
|
|
if not k or k[0] == '_': cfgdict.pop(k)
|
|
|
|
if not cfgdict: continue
|
|
|
|
filename = bsys.join(_CFG_DIR, "%s%s" % (mainkey, _EXT))
|
|
f = file(filename, 'w')
|
|
output = _dict_to_str(mainkey, _sanitize(cfgdict))
|
|
f.write(output)
|
|
f.close()
|
|
|