Commit 72d509e4 authored by Godefroid Chapelle's avatar Godefroid Chapelle

Merge commit 'gotcha-annotate' into l-trunk

Conflicts:
	CHANGES.txt
	src/zc/buildout/buildout.py
parent cd4b3e45
Change History Change History
************** **************
- Added annotate command for annotated sections. Displays sections key-value pairs
along with the value origin.
1.3.0 (2009-06-22) 1.3.0 (2009-06-22)
================== ==================
......
...@@ -29,6 +29,8 @@ import urllib2 ...@@ -29,6 +29,8 @@ import urllib2
import ConfigParser import ConfigParser
import UserDict import UserDict
import glob import glob
import copy
import pkg_resources import pkg_resources
import zc.buildout import zc.buildout
...@@ -65,7 +67,48 @@ class MissingSection(zc.buildout.UserError, KeyError): ...@@ -65,7 +67,48 @@ 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 = {
def _annotate_section(section, note):
for key in section:
section[key] = (section[key], note)
return section
def _annotate(data, note):
for key in data:
data[key] = _annotate_section(data[key], note)
return data
def _print_annotate(data):
sections = data.keys()
sections.sort()
print
print "Annotated sections"
print "="*len("Annotated sections")
for section in sections:
print
print '[%s]' % section
keys = data[section].keys()
keys.sort()
for key in keys:
value, files = data[section][key]
print "%s=%s" % (key, value)
for file in files.split():
print " " + file
print
print
def _unannotate_section(section):
for key in section:
value, note = section[key]
section[key] = value
return section
def _unannotate(data):
for key in data:
data[key] = _unannotate_section(data[key])
return data
_buildout_default_options = _annotate_section({
'eggs-directory': 'eggs', 'eggs-directory': 'eggs',
'develop-eggs-directory': 'develop-eggs', 'develop-eggs-directory': 'develop-eggs',
'bin-directory': 'bin', 'bin-directory': 'bin',
...@@ -75,7 +118,8 @@ _buildout_default_options = { ...@@ -75,7 +118,8 @@ _buildout_default_options = {
'executable': sys.executable, 'executable': sys.executable,
'log-level': 'INFO', 'log-level': 'INFO',
'log-format': '', 'log-format': '',
} }, 'DEFAULT_VALUE')
class Buildout(UserDict.DictMixin): class Buildout(UserDict.DictMixin):
...@@ -101,13 +145,14 @@ class Buildout(UserDict.DictMixin): ...@@ -101,13 +145,14 @@ class Buildout(UserDict.DictMixin):
# Sigh. this model of a buildout nstance # Sigh. this model of a buildout nstance
# with methods is breaking down :( # with methods is breaking down :(
config_file = None config_file = None
data['buildout']['directory'] = '.' data['buildout']['directory'] = ('.', 'COMPUTED_VALUE')
else: else:
raise zc.buildout.UserError( raise zc.buildout.UserError(
"Couldn't open %s" % config_file) "Couldn't open %s" % config_file)
if config_file: if config_file:
data['buildout']['directory'] = os.path.dirname(config_file) data['buildout']['directory'] = (os.path.dirname(config_file),
'COMPUTED_VALUE')
else: else:
base = None base = None
...@@ -128,10 +173,11 @@ class Buildout(UserDict.DictMixin): ...@@ -128,10 +173,11 @@ class Buildout(UserDict.DictMixin):
options = data.get(section) options = data.get(section)
if options is None: if options is None:
options = data[section] = {} options = data[section] = {}
options[option] = value options[option] = value, "COMMAND_LINE_VALUE"
# The egg dire # The egg dire
self._raw = data self._annotated = copy.deepcopy(data)
self._raw = _unannotate(data)
self._data = {} self._data = {}
self._parts = [] self._parts = []
# provide some defaults before options are parsed # provide some defaults before options are parsed
...@@ -881,6 +927,9 @@ class Buildout(UserDict.DictMixin): ...@@ -881,6 +927,9 @@ class Buildout(UserDict.DictMixin):
runsetup = setup # backward compat. runsetup = setup # backward compat.
def annotate(self, args):
_print_annotate(self._annotated)
def __getitem__(self, section): def __getitem__(self, section):
__doing__ = 'Getting section %s.', section __doing__ = 'Getting section %s.', section
try: try:
...@@ -1205,6 +1254,8 @@ def _open(base, filename, seen): ...@@ -1205,6 +1254,8 @@ def _open(base, filename, seen):
extended_by = options.pop('extended-by', extended_by) extended_by = options.pop('extended-by', extended_by)
result[section] = options result[section] = options
result = _annotate(result, filename)
if extends: if extends:
extends = extends.split() extends = extends.split()
extends.reverse() extends.reverse()
...@@ -1249,14 +1300,21 @@ def _dists_sig(dists): ...@@ -1249,14 +1300,21 @@ def _dists_sig(dists):
def _update_section(s1, s2): def _update_section(s1, s2):
for k, v in s2.items(): for k, v in s2.items():
v2, note2 = v
if k.endswith('+'): if k.endswith('+'):
key = k.rstrip(' +') key = k.rstrip(' +')
s2[key] = "\n".join(s1.get(key, "").split('\n') + s2[k].split('\n')) v1, note1 = s1.get(key, ("", ""))
newnote = ' +'.join((note1, note2)).strip()
s2[key] = "\n".join((v1).split('\n') +
v2.split('\n')), newnote
del s2[k] del s2[k]
elif k.endswith('-'): elif k.endswith('-'):
key = k.rstrip(' -') key = k.rstrip(' -')
s2[key] = "\n".join([v for v in s1.get(key, "").split('\n') v1, note1 = s1.get(key, ("", ""))
if v not in s2[k].split('\n')]) newnote = ' -'.join((note1, note2)).strip()
s2[key] = ("\n".join(
[v for v in v1.split('\n')
if v not in v2.split('\n')]), newnote)
del s2[k] del s2[k]
s1.update(s2) s1.update(s2)
...@@ -1419,6 +1477,13 @@ Commands: ...@@ -1419,6 +1477,13 @@ Commands:
The script can be given either as a script path or a path to a The script can be given either as a script path or a path to a
directory containing a setup.py script. directory containing a setup.py script.
annotate
Display annotated sections. All sections are displayed, sorted
alphabetically. For each section, all key-value pairs are displayed,
sorted alphabetically, along with the origin of the value (file name or
COMPUTED_VALUE, DEFAULT_VALUE, COMMAND_LINE_VALUE).
""" """
def _help(): def _help():
print _usage print _usage
...@@ -1438,7 +1503,7 @@ def main(args=None): ...@@ -1438,7 +1503,7 @@ def main(args=None):
if args[0][0] == '-': if args[0][0] == '-':
op = orig_op = args.pop(0) op = orig_op = args.pop(0)
op = op[1:] op = op[1:]
while op and op[0] in 'vqhWUoOnND': while op and op[0] in 'vqhWUoOnNDA':
if op[0] == 'v': if op[0] == 'v':
verbosity += 10 verbosity += 10
elif op[0] == 'q': elif op[0] == 'q':
...@@ -1507,6 +1572,7 @@ def main(args=None): ...@@ -1507,6 +1572,7 @@ def main(args=None):
command = args.pop(0) command = args.pop(0)
if command not in ( if command not in (
'install', 'bootstrap', 'runsetup', 'setup', 'init', 'install', 'bootstrap', 'runsetup', 'setup', 'init',
'annotate',
): ):
_error('invalid command:', command) _error('invalid command:', command)
else: else:
......
...@@ -707,6 +707,54 @@ characters ":", "$", "%", "(", and ")". For now, it is a good idea to ...@@ -707,6 +707,54 @@ characters ":", "$", "%", "(", and ")". For now, it is a good idea to
keep section and option names simple, sticking to alphanumeric keep section and option names simple, sticking to alphanumeric
characters, hyphens, and periods. characters, hyphens, and periods.
Annotated sections
------------------
When used with the `annotate` command, buildout displays annotated sections.
All sections are displayed, sorted alphabetically. For each section,
all key-value pairs are displayed, sorted alphabetically, along with
the origin of the value (file name or COMPUTED_VALUE, DEFAULT_VALUE,
COMMAND_LINE_VALUE).
>>> print system(buildout+ ' annotate'), # doctest: +ELLIPSIS
<BLANKLINE>
Annotated sections
==================
<BLANKLINE>
[buildout]
bin-directory=bin
DEFAULT_VALUE
develop=recipes
.../_TEST_/sample-buildout/buildout.cfg
develop-eggs-directory=develop-eggs
DEFAULT_VALUE
directory=.../_TEST_/sample-buildout
COMPUTED_VALUE
eggs-directory=eggs
DEFAULT_VALUE
executable=...
DEFAULT_VALUE
installed=.installed.cfg
DEFAULT_VALUE
log-format=
DEFAULT_VALUE
log-level=INFO
DEFAULT_VALUE
parts=data-dir
.../_TEST_/sample-buildout/buildout.cfg
parts-directory=parts
DEFAULT_VALUE
python=buildout
DEFAULT_VALUE
<BLANKLINE>
[data-dir]
path=foo bins
.../_TEST_/sample-buildout/buildout.cfg
recipe=recipes:mkdir
.../_TEST_/sample-buildout/buildout.cfg
<BLANKLINE>
<BLANKLINE>
Variable substitutions Variable substitutions
---------------------- ----------------------
...@@ -1025,6 +1073,46 @@ Verify option values. ...@@ -1025,6 +1073,46 @@ Verify option values.
['a1 a2/na3 a4/na5', 'b1 b2 b3 b4', 'c1 c2/nc3 c4 c5', 'h1 h2'] ['a1 a2/na3 a4/na5', 'b1 b2 b3 b4', 'c1 c2/nc3 c4 c5', 'h1 h2']
Develop: '/sample-buildout/demo' Develop: '/sample-buildout/demo'
Annotated sections output shows which files are responsible for which
operations.
>>> print system(os.path.join('bin', 'buildout') + ' annotate'), # doctest: +ELLIPSIS
<BLANKLINE>
Annotated sections
==================
...
<BLANKLINE>
[part1]
option=a1 a2
a3 a4
a5
.../_TEST_/sample-buildout/base.cfg
+.../_TEST_/sample-buildout/extension1.cfg
+.../_TEST_/sample-buildout/extension2.cfg
recipe=
.../_TEST_/sample-buildout/base.cfg
<BLANKLINE>
[part2]
option=b1 b2 b3 b4
.../_TEST_/sample-buildout/base.cfg
-.../_TEST_/sample-buildout/extension1.cfg
-.../_TEST_/sample-buildout/extension2.cfg
recipe=
.../_TEST_/sample-buildout/base.cfg
<BLANKLINE>
[part3]
option=c1 c2
c3 c4 c5
.../_TEST_/sample-buildout/base.cfg
+.../_TEST_/sample-buildout/extension1.cfg
recipe=
.../_TEST_/sample-buildout/base.cfg
<BLANKLINE>
[part4]
option=h1 h2
.../_TEST_/sample-buildout/extension1.cfg
...
Cleanup. Cleanup.
>>> os.remove(os.path.join(sample_buildout, 'base.cfg')) >>> os.remove(os.path.join(sample_buildout, 'base.cfg'))
......
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