Commit 9a2c05ac authored by Jim Fulton's avatar Jim Fulton

Added an upload entry point for extensions.

Also fixed some spurious failures in the bootstrap test.
parent 522d9598
Change History
**************
1.2.2 (unreleased)
1.2.2 (2009-06-19)
==================
- Better Windows compatibility in test infrastructure.
......@@ -16,6 +16,8 @@ Change History
- fixed usage of 'relative_paths' keyword parameter on Windows
- Added an unload entry point for extensions.
1.2.1 (2009-03-18)
==================
......
......@@ -59,12 +59,7 @@ Let's try with an unknown version::
X
No local packages or download links found for zc.buildout==UNKNOWN
error: Could not find suitable distribution for Requirement.parse('zc.buildout==UNKNOWN')
Traceback (most recent call last):
File "bootstrap.py", line 78, in <module>
) == 0
AssertionError
<BLANKLINE>
X
...
Now let's try with `1.1.2`, which happens to exist::
......
......@@ -83,7 +83,7 @@ class Buildout(UserDict.DictMixin):
user_defaults=True, windows_restart=False, command=None):
__doing__ = 'Initializing.'
self.__windows_restart = windows_restart
# default options
......@@ -138,7 +138,7 @@ class Buildout(UserDict.DictMixin):
# because while parsing options those attributes might be
# used already (Gottfried Ganssauge)
buildout_section = data.get('buildout')
# Try to make sure we have absolute paths for standard
# directories. We do this before doing substitutions, in case
# a one of these gets read by another section. If any
......@@ -155,13 +155,13 @@ class Buildout(UserDict.DictMixin):
allow_hosts = buildout_section and buildout_section.get(
'allow-hosts', '*').split('\n')
self._allow_hosts = tuple([host.strip() for host in allow_hosts
self._allow_hosts = tuple([host.strip() for host in allow_hosts
if host.strip() != ''])
self._logger = logging.getLogger('zc.buildout')
self.offline = False
self.newest = True
##################################################################
## WARNING!!!
## ALL ATTRIBUTES MUST HAVE REASONABLE DEFAULTS AT THIS POINT
......@@ -173,9 +173,9 @@ class Buildout(UserDict.DictMixin):
# now reinitialize
links = options.get('find-links', '')
self._links = links and links.split() or ()
allow_hosts = options.get('allow-hosts', '*').split('\n')
self._allow_hosts = tuple([host.strip() for host in allow_hosts
self._allow_hosts = tuple([host.strip() for host in allow_hosts
if host.strip() != ''])
self._buildout_dir = options['directory']
......@@ -216,7 +216,7 @@ class Buildout(UserDict.DictMixin):
self._error('Invalid value for prefer-final option: %s',
prefer_final)
zc.buildout.easy_install.prefer_final(prefer_final=='true')
use_dependency_links = options.get('use-dependency-links', 'true')
if use_dependency_links not in ('true', 'false'):
self._error('Invalid value for use-dependency-links option: %s',
......@@ -243,7 +243,7 @@ class Buildout(UserDict.DictMixin):
download_cache = os.path.join(download_cache, 'dist')
if not os.path.isdir(download_cache):
os.mkdir(download_cache)
zc.buildout.easy_install.download_cache(download_cache)
install_from_cache = options.get('install-from-cache')
......@@ -335,7 +335,7 @@ class Buildout(UserDict.DictMixin):
installed_develop_eggs = self._develop()
installed_part_options['buildout']['installed_develop_eggs'
] = installed_develop_eggs
if installed_exists:
self._update_installed(
installed_develop_eggs=installed_develop_eggs)
......@@ -345,7 +345,7 @@ class Buildout(UserDict.DictMixin):
conf_parts = conf_parts and conf_parts.split() or []
installed_parts = installed_part_options['buildout']['parts']
installed_parts = installed_parts and installed_parts.split() or []
if install_args:
install_parts = install_args
uninstall_missing = False
......@@ -361,11 +361,11 @@ class Buildout(UserDict.DictMixin):
if self._log_level < logging.DEBUG:
sections = list(self)
sections.sort()
print
print
print 'Configuration data:'
for section in self._data:
_save_options(section, self[section], sys.stdout)
print
print
# compute new part recipe signatures
......@@ -493,7 +493,7 @@ class Buildout(UserDict.DictMixin):
if need_to_save_installed:
installed_part_options['buildout']['parts'] = (
' '.join(installed_parts))
' '.join(installed_parts))
self._save_installed_options(installed_part_options)
installed_exists = True
else:
......@@ -506,6 +506,8 @@ class Buildout(UserDict.DictMixin):
elif (not installed_parts) and installed_exists:
os.remove(self['buildout']['installed'])
self._unload_extensions()
def _update_installed(self, **buildout_options):
installed = self['buildout']['installed']
f = open(installed, 'a')
......@@ -533,7 +535,6 @@ class Buildout(UserDict.DictMixin):
self._uninstall(
installed_part_options[part]['__buildout_installed__'])
def _setup_directories(self):
__doing__ = 'Setting up buildout directories'
......@@ -564,7 +565,8 @@ class Buildout(UserDict.DictMixin):
setup = self._buildout_path(setup)
files = glob.glob(setup)
if not files:
self._logger.warn("Couldn't develop %r (not found)", setup)
self._logger.warn("Couldn't develop %r (not found)",
setup)
else:
files.sort()
for setup in files:
......@@ -581,7 +583,7 @@ class Buildout(UserDict.DictMixin):
if f not in old_files
]))
raise
else:
self._sanity_check_develop_eggs_files(dest, old_files)
return '\n'.join([os.path.join(dest, f)
......@@ -628,7 +630,7 @@ class Buildout(UserDict.DictMixin):
value = value.replace(k, v)
options[option] = value
result[section] = Options(self, section, options)
return result, True
else:
return ({'buildout': Options(self, 'buildout', {'parts': ''})},
......@@ -656,8 +658,8 @@ class Buildout(UserDict.DictMixin):
# Sigh. This is the exectable used to run the buildout
# and, of course, it's in use. Leave it.
):
raise
raise
def _install(self, part):
options = self[part]
recipe, entry = _recipe(options)
......@@ -701,7 +703,7 @@ class Buildout(UserDict.DictMixin):
buildout_handler.setFormatter(logging.Formatter('%(message)s'))
self._logger.propagate = False
self._logger.addHandler(buildout_handler)
handler.setFormatter(logging.Formatter(log_format))
root_logger.addHandler(handler)
......@@ -730,7 +732,7 @@ class Buildout(UserDict.DictMixin):
if not self.newest:
return
ws = zc.buildout.easy_install.install(
[
(spec + ' ' + self['buildout'].get(spec+'-version', '')).strip()
......@@ -774,8 +776,8 @@ class Buildout(UserDict.DictMixin):
if not __debug__:
args.insert(0, '-O')
args.insert(0, zc.buildout.easy_install._safe_arg (sys.executable))
os.execv(sys.executable, args)
os.execv(sys.executable, args)
self._logger.info("Upgraded:\n %s;\nrestarting.",
",\n ".join([("%s version %s"
% (dist.project_name, dist.version)
......@@ -784,7 +786,7 @@ class Buildout(UserDict.DictMixin):
]
),
)
# the new dist is different, so we've upgraded.
# Update the scripts and return True
zc.buildout.easy_install.scripts(
......@@ -831,6 +833,14 @@ class Buildout(UserDict.DictMixin):
for ep in pkg_resources.iter_entry_points('zc.buildout.extension'):
ep.load()(self)
def _unload_extensions(self):
__doing__ = 'Unloading extensions.'
specs = self['buildout'].get('extensions', '').split()
if specs:
for ep in pkg_resources.iter_entry_points(
'zc.buildout.unloadextension'):
ep.load()(self)
def setup(self, args):
if not args:
raise zc.buildout.UserError(
......@@ -854,13 +864,13 @@ class Buildout(UserDict.DictMixin):
))
if is_jython:
arg_list = list()
for a in args:
add_args.append(zc.buildout.easy_install._safe_arg(a))
subprocess.Popen([zc.buildout.easy_install._safe_arg(sys.executable)] + list(tsetup) +
arg_list).wait()
else:
os.spawnl(os.P_WAIT, sys.executable, zc.buildout.easy_install._safe_arg (sys.executable), tsetup,
*[zc.buildout.easy_install._safe_arg(a)
......@@ -886,7 +896,7 @@ class Buildout(UserDict.DictMixin):
options = Options(self, section, data)
self._data[section] = options
options._initialize()
return options
return options
def __setitem__(self, key, value):
raise NotImplementedError('__setitem__')
......@@ -951,7 +961,7 @@ class Options(UserDict.DictMixin):
def _initialize(self):
name = self.name
__doing__ = 'Initializing section %s.', name
# force substitutions
for k, v in self._raw.items():
if '${' in v:
......@@ -959,11 +969,11 @@ class Options(UserDict.DictMixin):
if self.name == 'buildout':
return # buildout section can never be a part
recipe = self.get('recipe')
if not recipe:
return
reqs, entry = _recipe(self._data)
buildout = self.buildout
recipe_class = _install_and_load(reqs, 'zc.buildout', entry, buildout)
......@@ -1035,7 +1045,7 @@ class Options(UserDict.DictMixin):
"The option name in substitution, %s,\n"
"has invalid characters."
% ref)
v = self.buildout[s[0]].get(s[1], None, seen)
if v is None:
raise MissingOption("Referenced option does not exist:", *s)
......@@ -1043,7 +1053,7 @@ class Options(UserDict.DictMixin):
subs.append('')
return ''.join([''.join(v) for v in zip(value[::2], subs)])
def __getitem__(self, key):
try:
return self._data[key]
......@@ -1147,7 +1157,7 @@ def _save_option(option, value, f):
if value.endswith('\n\t'):
value = value[:-2] + '%(__buildout_space_n__)s'
print >>f, option, '=', value
def _save_options(section, options, f):
print >>f, '[%s]' % section
items = options.items()
......@@ -1210,7 +1220,7 @@ def _open(base, filename, seen):
seen.pop()
return result
ignore_directories = '.svn', 'CVS'
def _dir_hash(dir):
......@@ -1226,7 +1236,7 @@ def _dir_hash(dir):
for name in filenames:
hash.update(open(os.path.join(dirpath, name)).read())
return hash.digest().encode('base64').strip()
def _dists_sig(dists):
result = []
for dist in dists:
......@@ -1248,7 +1258,7 @@ def _update_section(s1, s2):
s2[key] = "\n".join([v for v in s1.get(key, "").split('\n')
if v not in s2[k].split('\n')])
del s2[k]
s1.update(s2)
return s1
......@@ -1278,7 +1288,7 @@ def _doing():
if d:
doing.append(d)
tb = tb.tb_next
if doing:
sys.stderr.write('While:\n')
for d in doing:
......@@ -1335,13 +1345,13 @@ Options:
Don't read user defaults.
-o
Run in off-line mode. This is equivalent to the assignment
Run in off-line mode. This is equivalent to the assignment
buildout:offline=true.
-O
Run in non-off-line mode. This is equivalent to the assignment
Run in non-off-line mode. This is equivalent to the assignment
buildout:offline=false. This is the default buildout mode. The
-O option would normally be used to override a true offline
setting in a configuration file.
......@@ -1355,10 +1365,10 @@ Options:
-N
Run in non-newest mode. This is equivalent to the assignment
Run in non-newest mode. This is equivalent to the assignment
buildout:newest=false. With this setting, buildout will not seek
new distributions if installed distributions satisfy it's
requirements.
requirements.
-D
......@@ -1408,7 +1418,7 @@ Commands:
The script can be given either as a script path or a path to a
directory containing a setup.py script.
"""
def _help():
print _usage
......@@ -1450,7 +1460,7 @@ def main(args=None):
else:
_help()
op = op[1:]
if op[:1] in ('c', 't'):
op_ = op[:1]
op = op[1:]
......@@ -1527,8 +1537,8 @@ def main(args=None):
sys.stderr.write(_internal_error_template)
traceback.print_exception(*exc_info)
sys.exit(1)
finally:
logging.shutdown()
......
......@@ -2368,15 +2368,17 @@ parts:
Extensions
----------
An **experimental** feature allows code to be loaded and run after
A feature allows code to be loaded and run after
configuration files have been read but before the buildout has begun
any processing. The intent is to allow special plugins such as
urllib2 request handlers to be loaded.
To load an extension, we use the extensions option and list one or
more distribution requirements, on separate lines. The distributions
named will be loaded and any zc.buildout.extensions entry points found
will be called with the buildout as an argument.
named will be loaded and any ``zc.buildout.extension`` entry points found
will be called with the buildout as an argument. When buildout
finishes processing, any ``zc.buildout.unloadextension`` entry points
found will be called with the buildout as an argument.
Let's create a sample extension in our sample buildout created in the
previous section:
......@@ -2387,6 +2389,8 @@ previous section:
... """
... def ext(buildout):
... print 'ext', list(buildout)
... def unload(buildout):
... print 'unload', list(buildout)
... """)
>>> write(sample_bootstrapped, 'demo', 'setup.py',
......@@ -2395,7 +2399,10 @@ previous section:
...
... setup(
... name = "demo",
... entry_points = {'zc.buildout.extension': ['ext = demo:ext']},
... entry_points = {
... 'zc.buildout.extension': ['ext = demo:ext'],
... 'zc.buildout.unloadextension': ['ext = demo:unload'],
... },
... )
... """)
......@@ -2436,6 +2443,7 @@ We see that our extension is loaded and executed:
>>> print system(os.path.join(sample_bootstrapped, 'bin', 'buildout')),
ext ['buildout']
Develop: '/sample-bootstrapped/demo'
unload ['buildout']
Allow hosts
-----------
......
......@@ -2895,6 +2895,7 @@ def test_suite():
zc.buildout.testing.normalize_endings,
zc.buildout.testing.normalize_script,
normalize_bang,
(re.compile('Downloading.*setuptools.*egg\n'), ''),
]),
))
......
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