Edgewall Software

Ticket #8290: config-provider.patch

File config-provider.patch, 6.9 KB (added by Joachim Hoessler <hoessler@…>, 3 years ago)
  • trac/env.py

     
    3636from trac.versioncontrol import RepositoryManager 
    3737from trac.web.href import Href 
    3838 
    39 __all__ = ['Environment', 'IEnvironmentSetupParticipant', 'open_environment'] 
     39__all__ = ['Environment', 'IEnvironmentSetupParticipant', 'open_environment',  
     40           'IConfigurationProvider'] 
    4041 
    4142 
     43class IConfigurationProvider(Interface): 
     44    """Extension point interface for components that want to provide configuration 
     45    settings.""" 
     46 
     47    def sections(): 
     48        """Return a list of section names.""" 
     49 
     50    def has_section(section): 
     51        """Returns True if option exists in section.""" 
     52 
     53    def options(section): 
     54        """Return a list of `(name, value)` tuples for every option in the 
     55        specified section.""" 
     56 
     57    def has_option(section, option): 
     58        """Returns True if option exists in section.""" 
     59 
     60    def get(section, option): 
     61        """Return the value of the specified option. 
     62         
     63        Valid default input is a string. Returns a string. 
     64        """ 
     65 
     66 
    4267class IEnvironmentSetupParticipant(Interface): 
    4368    """Extension point interface for components that need to participate in the 
    4469    creation and upgrading of Trac environments, for example to create 
     
    7499     * wiki and ticket attachments. 
    75100    """    
    76101    setup_participants = ExtensionPoint(IEnvironmentSetupParticipant) 
     102    config_provider = ExtensionPoint(IConfigurationProvider) 
    77103 
    78104    shared_plugins_dir = PathOption('inherit', 'plugins_dir', '', 
    79105        """Path of the directory containing additional plugins. 
     
    210236        if create: 
    211237            for setup_participant in self.setup_participants: 
    212238                setup_participant.environment_created() 
     239        self.config.config_provider.extend(self.config_provider) 
    213240 
    214241    def component_activated(self, component): 
    215242        """Initialize additional member variables for components. 
  • trac/config.py

     
    4343        self.filename = filename 
    4444        self.parser = ConfigParser() 
    4545        self.parent = None 
     46        self.config_provider = [] 
    4647        self._lastmtime = 0 
    4748        self._sections = {} 
    4849        self.parse_if_needed() 
     
    145146        while parent: 
    146147            sections |= set(parent.parser.sections()) 
    147148            parent = parent.parent 
     149        for provider in self.config_provider: 
     150            sections |= set(provider.sections()) 
    148151        return sorted(sections) 
    149152 
    150153    def has_option(self, section, option): 
     
    162165            for parent_option, val in self.parent.options(section): 
    163166                if parent_option == option: 
    164167                    return True 
     168        # check additional provider 
     169        for provider in self.config_provider: 
     170            if provider.has_option(section, option): 
     171                return True 
    165172        # Check the registry 
    166173        if (section, option) in Option.registry: 
    167174            return True 
     
    253260        if self.config.parser.has_option(self.name, name): 
    254261            return True 
    255262        if self.config.parent: 
    256             return name in self.config.parent[self.name] 
     263            if name in self.config.parent[self.name]: 
     264                return True 
     265        for provider in self.config.config_provider: 
     266            if provider.has_option(self.name, name): 
     267                return True 
    257268        return False 
    258269 
    259270    def __iter__(self): 
     
    265276        if self.config.parent: 
    266277            for option in self.config.parent[self.name]: 
    267278                if option.lower() not in options: 
     279                    options.add(option.lower()) 
    268280                    yield option 
     281        for provider in self.config.config_provider: 
     282            if provider.has_section(self.name): 
     283                for option in provider.options(self.name): 
     284                    if option.lower() not in options: 
     285                        options.add(option.lower()) 
     286                        yield option 
    269287 
    270288    def __repr__(self): 
    271289        return '<Section [%s]>' % (self.name) 
     290     
     291    def _get(self, name): 
     292        if self.config.parser.has_option(self.name, name): 
     293            return self.config.parser.get(self.name, name) 
     294        elif self.config.parent: 
     295            return self.config.parent[self.name]._get(name) 
     296        return None 
     297         
    272298 
    273299    def get(self, name, default=''): 
    274300        """Return the value of the specified option. 
    275301         
    276302        Valid default input is a string. Returns a string. 
    277303        """ 
    278         if self.config.parser.has_option(self.name, name): 
    279             value = self.config.parser.get(self.name, name) 
    280         elif self.config.parent: 
    281             value = self.config.parent[self.name].get(name, default) 
    282         else: 
     304        value = self._get(name) 
     305 
     306        if not value: 
     307            for provider in self.config.config_provider: 
     308                if provider.has_option(self.name, name): 
     309                    value = provider.get(self.name, name) 
     310         
     311        if not value: 
    283312            option = Option.registry.get((self.name, name)) 
    284313            if option: 
    285314                value = option.default or default 
  • trac/tests/config.py

     
    244244        finally: 
    245245            os.remove(sitename) 
    246246 
     247    def test_with_provider(self): 
     248        class mock_provider(object): 
     249            def sections(self): 
     250                return ['a', 'b'] 
     251            def options(self, section): 
     252                if section == 'a': 
     253                    return ['option_a'] 
     254                if section == 'b': 
     255                    return ['option_b'] 
     256                else: 
     257                    return None 
     258            def has_section(self, section): 
     259                return section in self.sections() 
     260            def has_option(self, section, option): 
     261                return ((section == 'a' and option == 'option_a') 
     262                        or (section == 'b' and option == 'option_b')) 
     263            def get(self, section, option): 
     264                if section == 'a' and option == 'option_a': 
     265                    return 'y' 
     266                if section == 'b' and option == 'option_b': 
     267                    return 'z' 
     268        provider = mock_provider() 
     269        self._write(['[a]', 'option = x']) 
     270        config = self._read() 
     271        config.config_provider.append(provider) 
     272        self.assertEquals('x', config.get('a', 'option')) 
     273        self.assertEquals('y', config.get('a', 'option_a')) 
     274        self.assertEquals('z', config.get('b', 'option_b')) 
     275        self.assertEquals([('option', u'x'), ('option_a', u'y')], list(config.options('a'))) 
    247276 
    248277def suite(): 
    249278    return unittest.makeSuite(ConfigurationTestCase, 'test')