Index: third_party/mozprofile/mozprofile/prefs.py |
=================================================================== |
--- third_party/mozprofile/mozprofile/prefs.py (revision 0) |
+++ third_party/mozprofile/mozprofile/prefs.py (revision 0) |
@@ -0,0 +1,210 @@ |
+# This Source Code Form is subject to the terms of the Mozilla Public |
+# License, v. 2.0. If a copy of the MPL was not distributed with this file, |
+# You can obtain one at http://mozilla.org/MPL/2.0/. |
+ |
+""" |
+user preferences |
+""" |
+ |
+import os |
+import re |
+from ConfigParser import SafeConfigParser as ConfigParser |
+ |
+try: |
+ import json |
+except ImportError: |
+ import simplejson as json |
+ |
+class PreferencesReadError(Exception): |
+ """read error for prefrences files""" |
+ |
+ |
+class Preferences(object): |
+ """assembly of preferences from various sources""" |
+ |
+ def __init__(self, prefs=None): |
+ self._prefs = [] |
+ if prefs: |
+ self.add(prefs) |
+ |
+ def add(self, prefs, cast=False): |
+ """ |
+ - cast: whether to cast strings to value, e.g. '1' -> 1 |
+ """ |
+ # wants a list of 2-tuples |
+ if isinstance(prefs, dict): |
+ prefs = prefs.items() |
+ if cast: |
+ prefs = [(i, self.cast(j)) for i, j in prefs] |
+ self._prefs += prefs |
+ |
+ def add_file(self, path): |
+ """a preferences from a file""" |
+ self.add(self.read(path)) |
+ |
+ def __call__(self): |
+ return self._prefs |
+ |
+ @classmethod |
+ def cast(cls, value): |
+ """ |
+ interpolate a preference from a string |
+ from the command line or from e.g. an .ini file, there is no good way to denote |
+ what type the preference value is, as natively it is a string |
+ - integers will get cast to integers |
+ - true/false will get cast to True/False |
+ - anything enclosed in single quotes will be treated as a string with the ''s removed from both sides |
+ """ |
+ |
+ if not isinstance(value, basestring): |
+ return value # no op |
+ quote = "'" |
+ if value == 'true': |
+ return True |
+ if value == 'false': |
+ return False |
+ try: |
+ return int(value) |
+ except ValueError: |
+ pass |
+ if value.startswith(quote) and value.endswith(quote): |
+ value = value[1:-1] |
+ return value |
+ |
+ |
+ @classmethod |
+ def read(cls, path): |
+ """read preferences from a file""" |
+ |
+ section = None # for .ini files |
+ basename = os.path.basename(path) |
+ if ':' in basename: |
+ # section of INI file |
+ path, section = path.rsplit(':', 1) |
+ |
+ if not os.path.exists(path): |
+ raise PreferencesReadError("'%s' does not exist" % path) |
+ |
+ if section: |
+ try: |
+ return cls.read_ini(path, section) |
+ except PreferencesReadError: |
+ raise |
+ except Exception, e: |
+ raise PreferencesReadError(str(e)) |
+ |
+ # try both JSON and .ini format |
+ try: |
+ return cls.read_json(path) |
+ except Exception, e: |
+ try: |
+ return cls.read_ini(path) |
+ except Exception, f: |
+ for exception in e, f: |
+ if isinstance(exception, PreferencesReadError): |
+ raise exception |
+ raise PreferencesReadError("Could not recognize format of %s" % path) |
+ |
+ |
+ @classmethod |
+ def read_ini(cls, path, section=None): |
+ """read preferences from an .ini file""" |
+ |
+ parser = ConfigParser() |
+ parser.read(path) |
+ |
+ if section: |
+ if section not in parser.sections(): |
+ raise PreferencesReadError("No section '%s' in %s" % (section, path)) |
+ retval = parser.items(section, raw=True) |
+ else: |
+ retval = parser.defaults().items() |
+ |
+ # cast the preferences since .ini is just strings |
+ return [(i, cls.cast(j)) for i, j in retval] |
+ |
+ @classmethod |
+ def read_json(cls, path): |
+ """read preferences from a JSON blob""" |
+ |
+ prefs = json.loads(file(path).read()) |
+ |
+ if type(prefs) not in [list, dict]: |
+ raise PreferencesReadError("Malformed preferences: %s" % path) |
+ if isinstance(prefs, list): |
+ if [i for i in prefs if type(i) != list or len(i) != 2]: |
+ raise PreferencesReadError("Malformed preferences: %s" % path) |
+ values = [i[1] for i in prefs] |
+ elif isinstance(prefs, dict): |
+ values = prefs.values() |
+ else: |
+ raise PreferencesReadError("Malformed preferences: %s" % path) |
+ types = (bool, basestring, int) |
+ if [i for i in values |
+ if not [isinstance(i, j) for j in types]]: |
+ raise PreferencesReadError("Only bool, string, and int values allowed") |
+ return prefs |
+ |
+ @classmethod |
+ def read_prefs(cls, path, pref_setter='user_pref'): |
+ """read preferences from (e.g.) prefs.js""" |
+ |
+ comment = re.compile('/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/', re.MULTILINE) |
+ |
+ token = '##//' # magical token |
+ lines = [i.strip() for i in file(path).readlines() if i.strip()] |
+ _lines = [] |
+ for line in lines: |
+ if line.startswith('#'): |
+ continue |
+ if '//' in line: |
+ line = line.replace('//', token) |
+ _lines.append(line) |
+ string = '\n'.join(_lines) |
+ string = re.sub(comment, '', string) |
+ |
+ retval = [] |
+ def pref(a, b): |
+ retval.append((a, b)) |
+ lines = [i.strip().rstrip(';') for i in string.split('\n') if i.strip()] |
+ |
+ _globals = {'retval': retval, 'true': True, 'false': False} |
+ _globals[pref_setter] = pref |
+ for line in lines: |
+ try: |
+ eval(line, _globals, {}) |
+ except SyntaxError: |
+ print line |
+ raise |
+ |
+ # de-magic the token |
+ for index, (key, value) in enumerate(retval): |
+ if isinstance(value, basestring) and token in value: |
+ retval[index] = (key, value.replace(token, '//')) |
+ |
+ return retval |
+ |
+ @classmethod |
+ def write(_file, prefs, pref_string='user_pref("%s", %s);'): |
+ """write preferences to a file""" |
+ |
+ if isinstance(_file, basestring): |
+ f = file(_file, 'w') |
+ else: |
+ f = _file |
+ |
+ if isinstance(prefs, dict): |
+ prefs = prefs.items() |
+ |
+ for key, value in prefs: |
+ if value is True: |
+ print >> f, pref_string % (key, 'true') |
+ elif value is False: |
+ print >> f, pref_string % (key, 'false') |
+ elif isinstance(value, basestring): |
+ print >> f, pref_string % (key, repr(string(value))) |
+ else: |
+ print >> f, pref_string % (key, value) # should be numeric! |
+ |
+ if isinstance(_file, basestring): |
+ f.close() |
Property changes on: third_party/mozprofile/mozprofile/prefs.py |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |