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.
982
985
location_parts = location.rstrip('/').split('/')
984
987
for section in sections:
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
988
# location is a local path if possible, so we need to convert 'file://'
989
# urls in section names to local paths if necessary.
991
991
# This also avoids having file:///path be a more exact
992
992
# match than '/path'.
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
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
1001
997
if section.startswith('file://'):
1002
998
section_path = urlutils.local_path_from_url(section)
2270
2266
:returns: An iterable of (name, dict).
2272
2268
# 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)
2412
2414
self.location = location
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())
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.
2420
2431
filtered_sections = _iter_for_location_by_parts(
2421
2432
[s.id for s in sections], self.location)
2422
2433
iter_sections = iter(sections)
2423
2434
matching_sections = []
2435
if no_name_section is not None:
2436
matching_sections.append(
2437
LocationSection(no_name_section, 0, self.location))
2424
2438
for section_id, extra_path, length in filtered_sections:
2425
2439
# a section id is unique for a given store so it's safe to iterate
2428
2442
if section_id == section.id:
2429
2443
matching_sections.append(
2430
2444
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()
2431
2450
# We want the longest (aka more specific) locations first
2432
2451
sections = sorted(matching_sections,
2433
2452
key=lambda section: (section.length, section.id),
2477
2496
# FIXME: No caching of options nor sections yet -- vila 20110503
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.
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
2482
2502
for section_or_callable in self.sections_def:
2483
2503
# Each section can expand to multiple ones when a callable is used
2484
2504
if callable(section_or_callable):
2498
2518
This is where we guarantee that the mutable section is lazily loaded:
2499
2519
this means we won't load the corresponding store before setting a value
2500
2520
or deleting an option. In practice the store will often be loaded but
2501
this allows catching some programming errors.
2521
this allows helps catching some programming errors.
2503
2523
section = self.store.get_mutable_section(self.mutable_section_name)
2518
2538
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],
2521
2571
class cmd_config(commands.Command):
2522
2572
__doc__ = """Display, set or remove a configuration option.