예제 #1
0
    def test_default(self):
        config = Configuration(self.filename)
        self.assertEquals('', config.get('a', 'option'))
        self.assertEquals('value', config.get('a', 'option', 'value'))

        config.setdefault('a', 'option', 'value')
        self.assertEquals('value', config.get('a', 'option'))
예제 #2
0
    def test_read_and_get(self):
        configfile = open(self.filename, 'w')
        configfile.writelines(['[a]\n', 'option = x\n', '\n'])
        configfile.close()

        config = Configuration(self.filename)
        self.assertEquals('x', config.get('a', 'option'))
        self.assertEquals('x', config.get('a', 'option', 'y'))
예제 #3
0
    def test_reparse(self):
        configfile = open(self.filename, 'w')
        configfile.writelines(['[a]\n', 'option = x\n', '\n'])
        configfile.close()

        config = Configuration(self.filename)
        self.assertEquals('x', config.get('a', 'option'))
        time.sleep(1)  # needed because of low mtime granularity

        configfile = open(self.filename, 'w')
        configfile.write('[a]\noption = y')
        configfile.close()
        config.parse_if_needed()
        self.assertEquals('y', config.get('a', 'option'))
예제 #4
0
    def test_set_and_save(self):
        configfile = open(self.filename, 'w')
        configfile.close()

        config = Configuration(self.filename)
        config.set('a', 'option', 'x')
        self.assertEquals('x', config.get('a', 'option'))
        config.save()

        configfile = open(self.filename, 'r')
        self.assertEquals(['[a]\n', 'option = x\n', '\n'],
                          configfile.readlines())
        configfile.close()
예제 #5
0
 def writeconfig(self, filepath, dicts=[]):
     """Writes or updates a config file. A list of dictionaries is used so
     that options for different aspects of the configuration can be kept
     separate while being able to update the same sections. Note that the
     result is order dependent where two dictionaries update the same option.
     """
     config = Configuration(filepath)
     file_changed = False
     for data in dicts:
         for section, options in data.iteritems():
             for key, value in options.iteritems():
                 if config.get(section, key, None) != value:
                     # This should be expected to generate a false positive
                     # when two dictionaries update the same option
                     file_changed = True
                 config.set(section, key, value)
     if file_changed:
         if os.path.exists(filepath):
             backupfile(filepath)
         config.save()
예제 #6
0
 def writeconfig(self, filepath, dicts=[]):
     """Writes or updates a config file. A list of dictionaries is used so
     that options for different aspects of the configuration can be kept
     separate while being able to update the same sections. Note that the
     result is order dependent where two dictionaries update the same option.
     """
     config = Configuration(filepath)
     file_changed = False
     for data in dicts:
         for section, options in data.iteritems():
             for key, value in options.iteritems():
                 if config.get(section, key, None) != value:
                     # This should be expected to generate a false positive
                     # when two dictionaries update the same option
                     file_changed = True
                 config.set(section, key, value)
     if file_changed:
         if os.path.exists(filepath):
             backupfile(filepath)
         config.save()
예제 #7
0
def diff(file1, file2, ignored_sections=None, ignore_absent=False):
    """
    :param file1: Filename
    :param file2: Filename
    :param list ignored_sections: List of ignored sections
    :param bool ignore_absent: Disables absent key reporting
    """
    if ignored_sections is None:
        ignored_sections = []

    if not os.path.exists(file1):
        raise ValueError('file %s does not exists' % file1)
    if not os.path.exists(file2):
        raise ValueError('file %s does not exists' % file2)

    conf1 = Configuration(file1)
    conf2 = Configuration(file2)

    fn1 = os.path.split(file1)[1]
    fn2 = os.path.split(file2)[1]

    conf1_sections = set(conf1.sections()) - set(ignored_sections)
    conf2_sections = set(conf2.sections()) - set(ignored_sections)

    for section in conf1.sections():
        if section not in conf2_sections:
            print 'SECTION: %s not in %s' % (section, fn2)

    default = object()
    for section in conf1_sections:
        for key, value1 in conf1.options(section):
            if not conf2.has_option(section, key):
                if not ignore_absent:
                    print '[%s] %s = %s is ABSENT from %s (but exists in %s)' % (
                        section, key, value1, fn2, fn1)
            else:
                value2 = conf2.get(section, key, default)
                if value2 != value1 and value2 is not default:
                    print '[%s] %s = %s -> %s (%s -> %s)' % (
                        section, key, value1, value2, fn1, fn2)
예제 #8
0
def diff(file1, file2, ignored_sections=None, ignore_absent=False):
    """
    :param file1: Filename
    :param file2: Filename
    :param list ignored_sections: List of ignored sections
    :param bool ignore_absent: Disables absent key reporting
    """
    if ignored_sections is None:
        ignored_sections = []

    if not os.path.exists(file1):
        raise ValueError("file %s does not exists" % file1)
    if not os.path.exists(file2):
        raise ValueError("file %s does not exists" % file2)

    conf1 = Configuration(file1)
    conf2 = Configuration(file2)

    fn1 = os.path.split(file1)[1]
    fn2 = os.path.split(file2)[1]

    conf1_sections = set(conf1.sections()) - set(ignored_sections)
    conf2_sections = set(conf2.sections()) - set(ignored_sections)

    for section in conf1.sections():
        if section not in conf2_sections:
            print "SECTION: %s not in %s" % (section, fn2)

    default = object()
    for section in conf1_sections:
        for key, value1 in conf1.options(section):
            if not conf2.has_option(section, key):
                if not ignore_absent:
                    print "[%s] %s = %s is ABSENT from %s (but exists in %s)" % (section, key, value1, fn2, fn1)
            else:
                value2 = conf2.get(section, key, default)
                if value2 != value1 and value2 is not default:
                    print "[%s] %s = %s -> %s (%s -> %s)" % (section, key, value1, value2, fn1, fn2)
예제 #9
0
 def get_home_config(self, mainchapter, subchapter):
     syspath = self.conf.getEnvironmentSysPath("home")
     getconf = Configuration(syspath + '/conf/trac.ini')
     return getconf.get(mainchapter, subchapter)
예제 #10
0
class Environment(Component, ComponentManager):
    """Trac stores project information in a Trac environment.

    A Trac environment consists of a directory structure containing among other
    things:
     * a configuration file.
     * an SQLite database (stores tickets, wiki pages...)
     * Project specific templates and wiki macros.
     * wiki and ticket attachments.
    """   
    setup_participants = ExtensionPoint(IEnvironmentSetupParticipant)

    def __init__(self, path, create=False, db_str=None):
        """Initialize the Trac environment.
        
        @param path:   the absolute path to the Trac environment
        @param create: if `True`, the environment is created and populated with
                       default data; otherwise, the environment is expected to
                       already exist.
        @param db_str: the database connection string
        """
        ComponentManager.__init__(self)

        self.path = path
        self.__cnx_pool = None
        if create:
            self.create(db_str)
        else:
            self.verify()
            self.load_config()
        self.setup_log()

        from trac.loader import load_components
        load_components(self)

        if create:
            for setup_participant in self.setup_participants:
                setup_participant.environment_created()

    def component_activated(self, component):
        """Initialize additional member variables for components.
        
        Every component activated through the `Environment` object gets three
        member variables: `env` (the environment object), `config` (the
        environment configuration) and `log` (a logger object)."""
        component.env = self
        component.config = self.config
        component.log = self.log

    def is_component_enabled(self, cls):
        """Implemented to only allow activation of components that are not
        disabled in the configuration.
        
        This is called by the `ComponentManager` base class when a component is
        about to be activated. If this method returns false, the component does
        not get activated."""
        if not isinstance(cls, (str, unicode)):
            component_name = (cls.__module__ + '.' + cls.__name__).lower()
        else:
            component_name = cls.lower()

        rules = [(name.lower(), value.lower() in ('enabled', 'on'))
                 for name, value in self.config.options('components')]
        rules.sort(lambda a, b: -cmp(len(a[0]), len(b[0])))

        for pattern, enabled in rules:
            if component_name == pattern or pattern.endswith('*') \
                    and component_name.startswith(pattern[:-1]):
                return enabled

        # By default, all components in the trac package are enabled
        return component_name.startswith('trac.')

    def verify(self):
        """Verify that the provided path points to a valid Trac environment
        directory."""
        fd = open(os.path.join(self.path, 'VERSION'), 'r')
        assert fd.read(26) == 'Trac Environment Version 1'
        fd.close()

    def get_db_cnx(self):
        """Return a database connection from the connection pool."""
        if not self.__cnx_pool:
            self.__cnx_pool = db.get_cnx_pool(self)
        return self.__cnx_pool.get_cnx()

    def shutdown(self):
        """Close the environment."""
        if self.__cnx_pool:
            self.__cnx_pool.shutdown()
            self.__cnx_pool = None

    def get_repository(self, authname=None):
        """Return the version control repository configured for this
        environment.
        
        The repository is wrapped in a `CachedRepository`.
        
        @param authname: user name for authorization
        """
        from trac.versioncontrol.cache import CachedRepository
        from trac.versioncontrol.svn_authz import SubversionAuthorizer
        from trac.versioncontrol.svn_fs import SubversionRepository
        repos_dir = self.config.get('trac', 'repository_dir')
        if not repos_dir:
            raise EnvironmentError, 'Path to repository not configured'
        authz = None
        if authname:
            authz = SubversionAuthorizer(self, authname)
        repos = SubversionRepository(repos_dir, authz, self.log)
        return CachedRepository(self.get_db_cnx(), repos, authz, self.log)

    def create(self, db_str=None):
        """Create the basic directory structure of the environment, initialize
        the database and populate the configuration file with default values."""
        def _create_file(fname, data=None):
            fd = open(fname, 'w')
            if data: fd.write(data)
            fd.close()

        # Create the directory structure
        os.mkdir(self.path)
        os.mkdir(self.get_log_dir())
        os.mkdir(self.get_htdocs_dir())
        os.mkdir(os.path.join(self.path, 'plugins'))
        os.mkdir(os.path.join(self.path, 'wiki-macros'))

        # Create a few files
        _create_file(os.path.join(self.path, 'VERSION'),
                     'Trac Environment Version 1\n')
        _create_file(os.path.join(self.path, 'README'),
                     'This directory contains a Trac environment.\n'
                     'Visit http://trac.edgewall.com/ for more information.\n')

        # Setup the default configuration
        os.mkdir(os.path.join(self.path, 'conf'))
        _create_file(os.path.join(self.path, 'conf', 'trac.ini'))
        self.load_config()
        for section, name, value in db_default.default_config:
            self.config.set(section, name, value)
        self.config.set('trac', 'database', db_str)
        self.config.save()

        # Create the database
        db.init_db(self.path, db_str)

    def get_version(self, db=None):
        """Return the current version of the database."""
        if not db:
            db = self.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("SELECT value FROM system WHERE name='database_version'")
        row = cursor.fetchone()
        return row and int(row[0])

    def load_config(self):
        """Load the configuration file."""
        self.config = Configuration(os.path.join(self.path, 'conf', 'trac.ini'))
        for section, name, value in db_default.default_config:
            self.config.setdefault(section, name, value)

    def get_templates_dir(self):
        """Return absolute path to the templates directory."""
        return os.path.join(self.path, 'templates')

    def get_htdocs_dir(self):
        """Return absolute path to the htdocs directory."""
        return os.path.join(self.path, 'htdocs')

    def get_log_dir(self):
        """Return absolute path to the log directory."""
        return os.path.join(self.path, 'log')

    def setup_log(self):
        """Initialize the logging sub-system."""
        from trac.log import logger_factory
        logtype = self.config.get('logging', 'log_type')
        loglevel = self.config.get('logging', 'log_level')
        logfile = self.config.get('logging', 'log_file')
        if not os.path.isabs(logfile):
            logfile = os.path.join(self.get_log_dir(), logfile)
        logid = self.path # Env-path provides process-unique ID
        self.log = logger_factory(logtype, logfile, loglevel, logid)

    def get_known_users(self, cnx=None):
        """Generator that yields information about all known users, i.e. users
        that have logged in to this Trac environment and possibly set their name
        and email.

        This function generates one tuple for every user, of the form
        (username, name, email) ordered alpha-numerically by username.

        @param cnx: the database connection; if ommitted, a new connection is
                    retrieved
        """
        if not cnx:
            cnx = self.get_db_cnx()
        cursor = cnx.cursor()
        cursor.execute("SELECT DISTINCT s.sid, n.var_value, e.var_value "
                       "FROM session AS s "
                       " LEFT JOIN session AS n ON (n.sid=s.sid "
                       "  AND n.authenticated=1 AND n.var_name = 'name') "
                       " LEFT JOIN session AS e ON (e.sid=s.sid "
                       "  AND e.authenticated=1 AND e.var_name = 'email') "
                       "WHERE s.authenticated=1 ORDER BY s.sid")
        for username,name,email in cursor:
            yield username, name, email

    def backup(self, dest=None):
        """Simple SQLite-specific backup of the database.

        @param dest: Destination file; if not specified, the backup is stored in
                     a file called db_name.trac_version.bak
        """
        import shutil

        db_str = self.config.get('trac', 'database')
        if not db_str.startswith('sqlite:'):
            raise EnvironmentError, 'Can only backup sqlite databases'
        db_name = os.path.join(self.path, db_str[7:])
        if not dest:
            dest = '%s.%i.bak' % (db_name, self.get_version())
        shutil.copy (db_name, dest)

    def needs_upgrade(self):
        """Return whether the environment needs to be upgraded."""
        db = self.get_db_cnx()
        for participant in self.setup_participants:
            if participant.environment_needs_upgrade(db):
                self.log.warning('Component %s requires environment upgrade',
                                 participant)
                return True
        return False

    def upgrade(self, backup=False, backup_dest=None):
        """Upgrade database.
        
        Each db version should have its own upgrade module, names
        upgrades/dbN.py, where 'N' is the version number (int).

        @param backup: whether or not to backup before upgrading
        @param backup_dest: name of the backup file
        @return: whether the upgrade was performed
        """
        db = self.get_db_cnx()

        upgraders = []
        for participant in self.setup_participants:
            if participant.environment_needs_upgrade(db):
                upgraders.append(participant)
        if not upgraders:
            return False

        if backup:
            self.backup(backup_dest)
        for participant in upgraders:
            participant.upgrade_environment(db)
        db.commit()

        # Database schema may have changed, so close all connections
        self.shutdown()

        return True
예제 #11
0
class MockEnvironment(Environment):
    """
    An mock Environment object which does not need real environment.
    Useful for when needing real environment like access to loaded plugins etc
    but no environment is at hand. Looks like normal project by default but can be
    made to look like home project environment or hybrid of both.

    .. WARNING:: Be careful when using this!
    """
    def __init__(self, config_file=None, enabled_plugins=None, path=None):
        """
        :param str config_file: path to the main configuration file.
            Defaults to ``/etc/trac/project.ini`` which is normal project configuration.
        :param list enabled_plugins:
            An explicit list of plugins to load, instead of reading enabled [components]
            from ``config_file``. If empty list is given no plugins are loaded.
            However plugins can be still listed via ``extra_plugins`` arg.
        :param str path: path to the imaginary trac location.
        """
        if config_file is None:
            # TODO: switch to some constant when can be done without conf
            from multiproject.core.configuration import conf
            config_file = conf.config_file

        # From Environment.setup_config:
        self.config = Configuration(config_file)

        if path is None:
            path = os.path.join(
                self.config.get('multiproject', 'sys_projects_root'),
                '__mock_environment__')
        if enabled_plugins is not None:
            # explicit list given, disable all from configuration
            for key, val in self.config.options('components'):
                self.config.remove('components', key)
            # and replace with the given list
            for plugin in enabled_plugins:
                self.config.set('components', plugin, u'enabled')

        # We override the Environment.__init__ here.

        # Environment.__init__ is as follows:

        # ComponentManager.__init__(self)
        #
        # self.path = path
        # self.systeminfo = []
        # self._href = self._abs_href = None
        #
        # if create:
        #     self.create(options)
        # else:
        #     self.verify()
        #     self.setup_config()
        #
        # if create:
        #     for setup_participant in self.setup_participants:
        #         setup_participant.environment_created()

        # The Environment.setup_config is as follows:

        # self.config = Configuration(os.path.join(self.path, 'conf',
        #         'trac.ini'))
        #         self.setup_log()
        #         from trac.loader import load_components
        #         plugins_dir = self.shared_plugins_dir
        #         load_components(self, plugins_dir and (plugins_dir,))

        # We use suitable lines from these as follows:

        # From Environment.__init__:
        ComponentManager.__init__(self)

        self.path = path
        self.systeminfo = []
        self._href = self._abs_href = None

        # Our own plugin hack ends here, and setup_config lines continue here
        self.setup_log()
        from trac.loader import load_components
        load_components(self)
예제 #12
0
 def __init__(self):
     self.port = str(Configuration.get(self.config, "trachat", "port", "8081"))
     t = TraChatPlugin.thread()
     t.port(self.port)
     t.start()
예제 #13
0
class MockEnvironment(Environment):
    """
    An mock Environment object which does not need real environment.
    Useful for when needing real environment like access to loaded plugins etc
    but no environment is at hand. Looks like normal project by default but can be
    made to look like home project environment or hybrid of both.

    .. WARNING:: Be careful when using this!
    """
    def __init__(self, config_file=None, enabled_plugins=None, path=None):
        """
        :param str config_file: path to the main configuration file.
            Defaults to ``/etc/trac/project.ini`` which is normal project configuration.
        :param list enabled_plugins:
            An explicit list of plugins to load, instead of reading enabled [components]
            from ``config_file``. If empty list is given no plugins are loaded.
            However plugins can be still listed via ``extra_plugins`` arg.
        :param str path: path to the imaginary trac location.
        """
        if config_file is None:
            # TODO: switch to some constant when can be done without conf
            from multiproject.core.configuration import conf
            config_file = conf.config_file

        # From Environment.setup_config:
        self.config = Configuration(config_file)

        if path is None:
            path = os.path.join(self.config.get('multiproject', 'sys_projects_root'), '__mock_environment__')
        if enabled_plugins is not None:
            # explicit list given, disable all from configuration
            for key, val in self.config.options('components'):
                self.config.remove('components', key)
            # and replace with the given list
            for plugin in enabled_plugins:
                self.config.set('components', plugin, u'enabled')

        # We override the Environment.__init__ here.

        # Environment.__init__ is as follows:

        # ComponentManager.__init__(self)
        #
        # self.path = path
        # self.systeminfo = []
        # self._href = self._abs_href = None
        #
        # if create:
        #     self.create(options)
        # else:
        #     self.verify()
        #     self.setup_config()
        #
        # if create:
        #     for setup_participant in self.setup_participants:
        #         setup_participant.environment_created()

        # The Environment.setup_config is as follows:

        # self.config = Configuration(os.path.join(self.path, 'conf',
        #         'trac.ini'))
        #         self.setup_log()
        #         from trac.loader import load_components
        #         plugins_dir = self.shared_plugins_dir
        #         load_components(self, plugins_dir and (plugins_dir,))

        # We use suitable lines from these as follows:

        # From Environment.__init__:
        ComponentManager.__init__(self)

        self.path = path
        self.systeminfo = []
        self._href = self._abs_href = None

        # Our own plugin hack ends here, and setup_config lines continue here
        self.setup_log()
        from trac.loader import load_components
        load_components(self)
예제 #14
0
 def get_home_config(self, mainchapter, subchapter):
     syspath = self.conf.getEnvironmentSysPath("home")
     getconf = Configuration(syspath + '/conf/trac.ini')
     return getconf.get(mainchapter, subchapter)