Commit 01c6e19e authored by Jim Fulton's avatar Jim Fulton

Print warnings of unused options in the buildout and installed-part

sections.
parent b0ec0009
...@@ -23,6 +23,8 @@ Change History ...@@ -23,6 +23,8 @@ Change History
Feature Changes Feature Changes
--------------- ---------------
Improved error reporting and debugging support:
- Added "logical tracebacks" that show functionally what the buildout - Added "logical tracebacks" that show functionally what the buildout
was doing when an error occurs. Don't show a Python traceback was doing when an error occurs. Don't show a Python traceback
unless the -D option is used. unless the -D option is used.
...@@ -30,6 +32,10 @@ Feature Changes ...@@ -30,6 +32,10 @@ Feature Changes
- Added a -D option that causes the buildout to print a traceback and - Added a -D option that causes the buildout to print a traceback and
start the pdb post-mortem debugger when an error occurs. start the pdb post-mortem debugger when an error occurs.
- Warnings are printed for unused options in the buildout section and
installed-part sections. This should make it easier to catch option
misspellings.
1.0.0b21 (2007-03-06) 1.0.0b21 (2007-03-06)
===================== =====================
......
...@@ -56,6 +56,17 @@ class MissingSection(zc.buildout.UserError, KeyError): ...@@ -56,6 +56,17 @@ class MissingSection(zc.buildout.UserError, KeyError):
def __str__(self): def __str__(self):
return "The referenced section, %r, was not defined." % self[0] return "The referenced section, %r, was not defined." % self[0]
_buildout_default_options = {
'eggs-directory': 'eggs',
'develop-eggs-directory': 'develop-eggs',
'bin-directory': 'bin',
'parts-directory': 'parts',
'installed': '.installed.cfg',
'python': 'buildout',
'executable': sys.executable,
'log-level': 'INFO',
'log-format': '%(name)s: %(message)s',
}
class Buildout(UserDict.DictMixin): class Buildout(UserDict.DictMixin):
...@@ -67,17 +78,7 @@ class Buildout(UserDict.DictMixin): ...@@ -67,17 +78,7 @@ class Buildout(UserDict.DictMixin):
self.__windows_restart = windows_restart self.__windows_restart = windows_restart
# default options # default options
data = dict(buildout={ data = dict(buildout=_buildout_default_options.copy())
'eggs-directory': 'eggs',
'develop-eggs-directory': 'develop-eggs',
'bin-directory': 'bin',
'parts-directory': 'parts',
'installed': '.installed.cfg',
'python': 'buildout',
'executable': sys.executable,
'log-level': 'INFO',
'log-format': '%(name)s: %(message)s',
})
if not _isurl(config_file): if not _isurl(config_file):
config_file = os.path.abspath(config_file) config_file = os.path.abspath(config_file)
...@@ -108,7 +109,6 @@ class Buildout(UserDict.DictMixin): ...@@ -108,7 +109,6 @@ class Buildout(UserDict.DictMixin):
options[option] = value options[option] = value
# The egg dire # The egg dire
self._raw = data self._raw = data
self._data = {} self._data = {}
self._parts = [] self._parts = []
...@@ -149,6 +149,10 @@ class Buildout(UserDict.DictMixin): ...@@ -149,6 +149,10 @@ class Buildout(UserDict.DictMixin):
if versions: if versions:
zc.buildout.easy_install.default_versions(dict(self[versions])) zc.buildout.easy_install.default_versions(dict(self[versions]))
# "Use" each of the defaults so they aren't reported as unused options.
for name in _buildout_default_options:
options[name]
def _buildout_path(self, *names): def _buildout_path(self, *names):
return os.path.join(self._buildout_dir, *names) return os.path.join(self._buildout_dir, *names)
...@@ -281,6 +285,9 @@ class Buildout(UserDict.DictMixin): ...@@ -281,6 +285,9 @@ class Buildout(UserDict.DictMixin):
self._uninstall_part(part, installed_part_options) self._uninstall_part(part, installed_part_options)
installed_parts = [p for p in installed_parts if p != part] installed_parts = [p for p in installed_parts if p != part]
# Check for unused buildout options:
_check_for_unused_options_in_section(self, 'buildout')
# install new parts # install new parts
for part in install_parts: for part in install_parts:
signature = self[part].pop('__buildout_signature__') signature = self[part].pop('__buildout_signature__')
...@@ -340,6 +347,7 @@ class Buildout(UserDict.DictMixin): ...@@ -340,6 +347,7 @@ class Buildout(UserDict.DictMixin):
installed_parts = [p for p in installed_parts if p != part] installed_parts = [p for p in installed_parts if p != part]
installed_parts.append(part) installed_parts.append(part)
_check_for_unused_options_in_section(self, part)
finally: finally:
installed_part_options['buildout']['parts'] = ( installed_part_options['buildout']['parts'] = (
...@@ -720,14 +728,17 @@ class Options(UserDict.DictMixin): ...@@ -720,14 +728,17 @@ class Options(UserDict.DictMixin):
self.buildout = buildout self.buildout = buildout
self.name = section self.name = section
self._raw = data self._raw = data
self._cooked = {}
self._data = {} self._data = {}
def _initialize(self): def _initialize(self):
name = self.name name = self.name
__doing__ = 'Initializing section %s', name __doing__ = 'Initializing section %s', name
# force substitutions # force substitutions
for k in self._raw: for k, v in self._raw.items():
self.get(k) if '${' in v:
self._dosub(k, v)
recipe = self.get('recipe') recipe = self.get('recipe')
if not recipe: if not recipe:
...@@ -741,15 +752,23 @@ class Options(UserDict.DictMixin): ...@@ -741,15 +752,23 @@ class Options(UserDict.DictMixin):
self.recipe = recipe_class(buildout, name, self) self.recipe = recipe_class(buildout, name, self)
buildout._parts.append(name) buildout._parts.append(name)
def _dosub(self, option, v):
__doing__ = 'Getting option %s:%s', self.name, option
seen = [(self.name, option)]
v = '$$'.join([self._sub(s, seen) for s in v.split('$$')])
self._cooked[option] = v
def get(self, option, default=None, seen=None): def get(self, option, default=None, seen=None):
try: try:
return self._data[option] return self._data[option]
except KeyError: except KeyError:
pass pass
v = self._raw.get(option) v = self._cooked.get(option)
if v is None: if v is None:
return default v = self._raw.get(option)
if v is None:
return default
__doing__ = 'Getting option %s:%s', self.name, option __doing__ = 'Getting option %s:%s', self.name, option
...@@ -826,6 +845,8 @@ class Options(UserDict.DictMixin): ...@@ -826,6 +845,8 @@ class Options(UserDict.DictMixin):
del self._raw[key] del self._raw[key]
if key in self._data: if key in self._data:
del self._data[key] del self._data[key]
if key in self._cooked:
del self._cooked[key]
elif key in self._data: elif key in self._data:
del self._data[key] del self._data[key]
else: else:
...@@ -836,7 +857,10 @@ class Options(UserDict.DictMixin): ...@@ -836,7 +857,10 @@ class Options(UserDict.DictMixin):
return list(self._raw) + [k for k in self._data if k not in raw] return list(self._raw) + [k for k in self._data if k not in raw]
def copy(self): def copy(self):
return dict([(k, self[k]) for k in self.keys()]) result = self._raw.copy()
result.update(self._cooked)
result.update(self._data)
return result
_spacey_nl = re.compile('[ \t\r\f\v]*\n[ \t\r\f\v\n]*' _spacey_nl = re.compile('[ \t\r\f\v]*\n[ \t\r\f\v\n]*'
'|' '|'
...@@ -1006,6 +1030,14 @@ recipe being used: ...@@ -1006,6 +1030,14 @@ recipe being used:
%s %s
""" """
def _check_for_unused_options_in_section(buildout, section):
options = buildout[section]
unused = [option for option in options._raw if option not in options._data]
if unused:
buildout._logger.warn("Unused options for %s: %s"
% (section, ' '.join(map(repr, unused)))
)
def _internal_error(v): def _internal_error(v):
sys.stderr.write(_internal_error_template % (v.__class__.__name__, v)) sys.stderr.write(_internal_error_template % (v.__class__.__name__, v))
......
...@@ -1340,7 +1340,51 @@ def download_errors(): ...@@ -1340,7 +1340,51 @@ def download_errors():
Getting distribution for setuptools Getting distribution for setuptools
Error: Download error... Error: Download error...
""" """
def whine_about_unused_options():
'''
>>> write('foo.py',
... """
... class Foo:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
... options['x']
...
... def install(self):
... self.options['y']
... return ()
... """)
>>> write('setup.py',
... """
... from setuptools import setup
... setup(name = "foo",
... entry_points = {'zc.buildout': ['default = foo:Foo']},
... )
... """)
>>> write('buildout.cfg',
... """
... [buildout]
... develop = .
... parts = foo
... a = 1
...
... [foo]
... recipe = foo
... x = 1
... y = 1
... z = 1
... """)
>>> print system(buildout),
buildout: Develop: /tmp/tmpsueWpG/_TEST_/sample-buildout/.
buildout: Unused options for buildout: 'a'
buildout: Installing foo
buildout: Unused options for foo: 'z'
'''
###################################################################### ######################################################################
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment