source: tags/0.2/config.py @ 335

Revision 219, 10.7 KB checked in by marc, 5 years ago (diff)

Updated version numbers and config values

  • Property svn:keywords set to Id Rev
Line 
1#! /usr/bin/env python
2# -*- coding: utf8 -*-
3#
4# Itaka is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# any later version.
8#
9# Itaka is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with Itaka; if not, write to the Free Software
16# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17#
18# Copyright 2003-2007 Marc E.
19# http://itaka.jardinpresente.com.ar
20#
21# $Id$
22
23""" Itaka configuration parser and engine """
24
25# It works by the core initiating the main instance, and the
26# modules accessing the global values variables set up by the initation.
27
28import ConfigParser, os, sys, shutil, traceback
29
30# Set up instance
31config = ConfigParser.ConfigParser()
32
33# Set up global variables (itakaglobals)
34
35#: Configuration file
36local_config = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "itaka.conf")
37
38#: Version
39version = "0.2"
40#: Revision
41revision = "$Rev$"
42
43#: System
44system = os.name
45
46#: Platform
47platform = None
48if (sys.platform.startswith("darwin")): platform = "darwin"
49
50#: Images directory
51image_dir = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "share/images/")
52#: To be changed on install to specify where the installed files actually are
53prefix = "/usr/share/itaka/images/"
54if os.path.exists(prefix):
55    image_dir = prefix
56
57# See if our images are there before starting
58if not os.path.exists(image_dir):
59    print "[*] ERROR: Could not find images directory '%s'" % (image_dir)
60    sys.exit(1)
61
62#: Save path for screenshots (system-specific specified later on)
63save_path = os.getcwd()
64
65if os.environ.get('HOME'):
66    save_path = os.path.join(os.environ.get('HOME'), ".itaka")
67else:
68    save_path = os.environ.get('TMP') or os.environ.get('TEMP')
69
70#: Availability of libnotify
71notifyavailable = False
72if system == "posix" and platform != "darwin":
73    try:
74        import pynotify
75        notifyavailable = True
76
77        if not pynotify.init("Itaka"):
78            print "[*] WARNING: Pynotify module is failing, disabling notifications"
79            notifyavailable = False
80    except ImportError:
81        print "[*] WARNING: Pynotify module is missing, disabling notifications"
82        notifyavailable = False
83
84#: Console output setting
85# 'normal' is for all normal operation mesages and warnings (not including errors)
86# 'debug' is for all messages through self.console.debug
87# 'quiet' is to quiet all errors and warnings. (totally quiet is in conjunction with 'normal')
88output = {'normal': False, 'debug': False, 'quiet': False}
89
90#: User's configuration values
91values = {}
92
93#: Default HTML header.
94# Putting <meta http-equiv="Refresh" content="5; url=http://localhost:8000"> is very useful for debugging
95headhtml = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
96<html>
97<head>
98<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
99<title>Itaka</title>
100</head>
101<body>
102<div id="main">
103'''
104
105#: Default HTML footer.
106footerhtml = '''
107</div>
108</body>
109</html>'''
110
111class ConfigParser:
112    """
113    Itaka configuration engine.
114    """
115
116    def __init__(self, arguments=None):
117        """
118        Configuration engine constructor. It also handles whether the L{output} setting is set to print everything to the console.
119
120        @type arguments: tuple
121        @param arguments: A tuple of sys.argv
122        """
123        if arguments is not None and len(arguments) > 1 and arguments[-1] == "-debug":
124            global output
125            output = {'normal': True, 'debug': True, 'quiet': False}
126            print "[*] Initializing in debug mode"
127
128        #: Default configuration sections and values
129        self.defaultoptions = (
130                {'server': (('port', 8000), ('authentication', False), ('username', 'user'), ('password', 'password'), ('notify', notifyavailable))},
131                {'screenshot': (('format', 'jpeg'), ('quality', 30), ('path', save_path), ('currentwindow', False), ('scale', False), ('scalepercent', 100))},
132                {'html': (('html', '<img src="screenshot" alt="If you are seeing this message it means there was an error in Itaka or you are using a text-only browser.">'), ('authfailure', '<p><strong>Sorry, but you cannot access this resource without authorization.</strong></p>'))}
133                )
134
135    def load(self):
136        """
137        Set up and load configuration
138
139        @rtype: dict
140        @return: Dictionary of configuration values.
141        """
142
143        self.configfile = None
144
145        # Check routine
146        if system in ("posix"):
147            if not (os.path.exists(os.path.join(os.environ['HOME'], ".itaka/itaka.conf"))):
148                self.create(os.path.join(os.environ['HOME'], ".itaka/itaka.conf"))
149            else:
150                self.configfile = os.path.join(os.environ['HOME'], ".itaka/itaka.conf")
151        elif (system == "nt"):
152            if not (os.path.exists(os.path.join(os.environ['APPDATA'], "itaka/itaka.ini"))):
153                self.create(os.path.join(os.environ['APPDATA'], "itaka/itaka.ini"))
154            else:
155                self.configfile = os.path.join(os.environ['APPDATA'], "itaka/itaka.ini")
156        else:
157            # Generic system/paths (using local)       
158            if (os.path.exists(local_config)):
159                self.configfile = local_config
160            else:       
161                self.create(local_config)
162        # Read and assign values from the configuration file
163        try:
164            config.read(self.configfile)
165            if output['normal']: print "[*] Read configuration (%s)" % (self.configfile)
166
167        except:
168            if output['normal']: print "[*] ERROR: Could not read configuration file (%s)" % (self.configfile)
169            if output['debug']: traceback.print_exc()
170
171        """ Retrieve values and return them as a dict """
172        global values
173        values = {}
174        # Get values as a dict and return it
175        for section in config.sections():
176            values[section] = dict(config.items(section))
177            # Convert 'False' and 'True' into booleans, and numbers into ints
178            # Add config options that are not there
179            for option, value in values[section].iteritems():
180                if value.strip() == "True":
181                    values[section][option] = True
182                elif value.strip() == "False":
183                    values[section][option] = False
184                elif value.isdigit():
185                    values[section][option] = int(value)
186
187        # Compare it to our default configuration set, to see if there is anything missing
188        # This is useful for updates, and corrupted files.
189        # NOTE: The setting of values[section][key] here is purely pragmatical, so we
190        # dont have to reload
191        brokenwarning = False
192        for configdict in self.defaultoptions:
193            for section in configdict:
194                if not values.has_key(section):
195                    if not output['quiet'] and not brokenwarning:
196                        print '[*] WARNING: Detected old or broken configuration file. Fixing'
197                        brokenwarning = True
198                    config.add_section(section)
199                    values[section] = {}
200                    for keyset in configdict[section]:
201                        key, val = keyset
202                        self.update(section, key, val)
203                        values[section][key] = val
204                else:
205                    # Check if all the key:vals are in the section
206                    for keyset in configdict[section]:
207                        key, val = keyset
208                        if not values[section].has_key(key):
209                            if not output['quiet'] and not brokenwarning: print "[*] WARNING: Detected old or broken configuration file. Fixing"
210                            self.update(section, key, val)
211                            values[section][key] = val
212                            brokenwarning = True
213        return values
214
215    def save(self, valuesdict):
216        """
217        Saves a dictionary containing the configuration.
218
219        @type valuesdict: dict
220        @param valuesdict: Dictionary of configuration.
221        """
222
223        # Unpack the dict into section, option, value
224        for section in valuesdict.keys():
225            for key, value in valuesdict[section].items():
226                config.set(section, key, value)
227
228        # Save
229        try:
230            config.write(open(self.configfile, 'w'))
231            if output['normal']: print "[*] Saving configuration... "   
232        except:         
233            if not output['quiet']: print "[*] ERROR: Could not write configuration file %s" % (self.configfile)
234            if output['debug']: traceback.print_exc()
235
236    def update(self, section, key, value):
237        """
238        Update a specific key's value.
239       
240        @type section: str
241        @param section: String of the section of the key to update.
242        @type key: str
243        @param key: String of the key to update.
244        @type value: str/int/bool
245        @param value: Value of the key to update.
246        """     
247       
248        config.set(section, key, value)
249       
250        try:
251            config.write(open(self.configfile, 'w'))
252            if output['debug']: print "[*] Updating configuration key %s to %s" % (key, value) 
253        except:
254            if not output['quiet']: print "[*] ERROR: Could not write configuration file %s" % (self.configfile)
255            if output['debug']: traceback.print_exc()
256
257    def create(self, path):
258        """
259        Create a configuration file from default values.
260       
261        @type path: str
262        @param path: Path to the configuration file.
263        """
264       
265        if output['normal']: print "[*] Creating default configuration..."
266
267        # Set default sections and options
268        for configdict in self.defaultoptions:
269            for section in configdict:
270                config.add_section(section)
271                for keyset in configdict[section]:
272                    key, val = keyset
273                    config.set(section, key, val)
274
275        # Check if the directory exists, if not create it
276        # and write the config file with its variables
277        if not (os.path.exists(os.path.dirname(path))):
278            shutil.os.mkdir(os.path.dirname(path))
279
280        try:
281            config.write(open(path, 'w'))
282        except:
283            if not output['quiet']: print "[*] ERROR: Could not write configuration file %s" % (path)
284            if output['debug']: traceback.print_exc()
285
286        self.configfile = path         
Note: See TracBrowser for help on using the repository browser.