978
978
number of path components in the section name, section is the section
979
979
name and extra_path is the difference between location and the section
982
``location`` will always be a local path and never a 'file://' url but the
983
section names themselves can be in either form.
985
982
location_parts = location.rstrip('/').split('/')
987
984
for section in sections:
988
# location is a local path if possible, so we need to convert 'file://'
989
# urls in section names to local paths if necessary.
985
# location is a local path if possible, so we need
986
# to convert 'file://' urls to local paths if necessary.
988
# FIXME: I don't think the above comment is still up to date,
989
# LocationConfig is always instantiated with an url -- vila 2011-04-07
991
991
# This also avoids having file:///path be a more exact
992
992
# match than '/path'.
994
# FIXME: This still raises an issue if a user defines both file:///path
995
# *and* /path. Should we raise an error in this case -- vila 20110505
994
# FIXME: Not sure about the above either, but since the path components
995
# are compared in sync, adding two empty components (//) is likely to
996
# trick the comparison and also trick the check on the number of
997
# components, so we *should* take only the relevant part of the url. On
998
# the other hand, this means 'file://' urls *can't* be used in sections
999
# so more work is probably needed -- vila 2011-04-07
997
1001
if section.startswith('file://'):
998
1002
section_path = urlutils.local_path_from_url(section)
2266
2270
:returns: An iterable of (name, dict).
2268
2272
# We need a loaded store
2271
except errors.NoSuchFile:
2272
# If the file doesn't exist, there is no sections
2274
2274
cobj = self._config_obj
2275
2275
if cobj.scalars:
2276
2276
yield self.readonly_section_class(None, cobj)
2410
2410
def __init__(self, store, location):
2411
2411
super(LocationMatcher, self).__init__(store)
2412
if location.startswith('file://'):
2413
location = urlutils.local_path_from_url(location)
2414
2412
self.location = location
2416
def _get_matching_sections(self):
2417
"""Get all sections matching ``location``."""
2418
# We slightly diverge from LocalConfig here by allowing the no-name
2419
# section as the most generic one and the lower priority.
2420
no_name_section = None
2422
# Filter out the no_name_section so _iter_for_location_by_parts can be
2423
# used (it assumes all sections have a name).
2424
for section in self.store.get_sections():
2425
if section.id is None:
2426
no_name_section = section
2428
sections.append(section)
2429
# Unfortunately _iter_for_location_by_parts deals with section names so
2430
# we have to resync.
2414
def get_sections(self):
2415
# Override the default implementation as we want to change the order
2417
# The following is a bit hackish but ensures compatibility with
2418
# LocationConfig by reusing the same code
2419
sections = list(self.store.get_sections())
2431
2420
filtered_sections = _iter_for_location_by_parts(
2432
2421
[s.id for s in sections], self.location)
2433
2422
iter_sections = iter(sections)
2434
2423
matching_sections = []
2435
if no_name_section is not None:
2436
matching_sections.append(
2437
LocationSection(no_name_section, 0, self.location))
2438
2424
for section_id, extra_path, length in filtered_sections:
2439
2425
# a section id is unique for a given store so it's safe to iterate
2442
2428
if section_id == section.id:
2443
2429
matching_sections.append(
2444
2430
LocationSection(section, length, extra_path))
2445
return matching_sections
2447
def get_sections(self):
2448
# Override the default implementation as we want to change the order
2449
matching_sections = self._get_matching_sections()
2450
2431
# We want the longest (aka more specific) locations first
2451
2432
sections = sorted(matching_sections,
2452
2433
key=lambda section: (section.length, section.id),
2496
2477
# FIXME: No caching of options nor sections yet -- vila 20110503
2498
# Ensuring lazy loading is achieved by delaying section matching (which
2499
# implies querying the persistent storage) until it can't be avoided
2500
# anymore by using callables to describe (possibly empty) section
2479
# Ensuring lazy loading is achieved by delaying section matching until
2480
# it can be avoided anymore by using callables to describe (possibly
2481
# empty) section lists.
2502
2482
for section_or_callable in self.sections_def:
2503
2483
# Each section can expand to multiple ones when a callable is used
2504
2484
if callable(section_or_callable):
2518
2498
This is where we guarantee that the mutable section is lazily loaded:
2519
2499
this means we won't load the corresponding store before setting a value
2520
2500
or deleting an option. In practice the store will often be loaded but
2521
this allows helps catching some programming errors.
2501
this allows catching some programming errors.
2523
2503
section = self.store.get_mutable_section(self.mutable_section_name)
2538
2518
return "<config.%s(%s)>" % (self.__class__.__name__, id(self))
2541
class GlobalStack(Stack):
2545
gstore = GlobalStore()
2546
super(GlobalStack, self).__init__([gstore.get_sections], gstore)
2549
class LocationStack(Stack):
2551
def __init__(self, location):
2552
lstore = LocationStore()
2553
matcher = LocationMatcher(lstore, location)
2554
gstore = GlobalStore()
2555
super(LocationStack, self).__init__(
2556
[matcher.get_sections, gstore.get_sections], lstore)
2559
class BranchStack(Stack):
2561
def __init__(self, branch):
2562
bstore = BranchStore(branch)
2563
lstore = LocationStore()
2564
matcher = LocationMatcher(lstore, branch.base)
2565
gstore = GlobalStore()
2566
super(BranchStack, self).__init__(
2567
[matcher.get_sections, bstore.get_sections, gstore.get_sections],
2571
2521
class cmd_config(commands.Command):
2572
2522
__doc__ = """Display, set or remove a configuration option.