Commit 3cd08544 authored by Jérome Perrin's avatar Jérome Perrin

Support multiple paths for shared

This will allow nested slapos where the inner slapos can re-use shared
parts from outer slapos, but not write into the outer shared parts.

For compatibility reasons, the syntax of the buildout option changed,
instead of the old ${buildout:shared-parts} that use to be one path, we
now use ${buildout:shared-part-list} as a \n separated list of paths.
All paths can be used to lookup existing parts, only the last one can be
used to install new parts.
There is no compatibility with the old option as it was not used much,
only in profiles which were not really compatible with shared options.
parent 8af74491
......@@ -30,7 +30,7 @@ Supported options
Specify the path in which this package is shared by many other
packages.
Shared-parts should be defined in [buildout] section
``shared-part-list`` should be defined in ``[buildout]`` section
Shared option is True or False
The package will be installed on path/name/hash of options.
......@@ -987,12 +987,19 @@ Install shared package
Use option ``shared`` to install a shared pacakge.
>>> import os
>>> _ = system('chmod -R u+w %(path)s && rm -rf %(path)s' % dict(path=join(os.path.dirname(__file__), 'shared')))
>>> _ = system('chmod -R u+w %(path)s && rm -rf %(path)s' % dict(
... path=join(os.path.dirname(__file__), 'shared')))
>>> shared_dir = join(os.path.dirname(__file__), 'shared')
>>> os.mkdir(shared_dir)
>>> _ = system('chmod -R u+w %(path)s && rm -rf %(path)s' % dict(
... path=join(os.path.dirname(__file__), 'another_shared_dir')))
>>> another_shared_dir = join(
... os.path.dirname(__file__), 'another_shared_dir')
>>> os.mkdir(another_shared_dir)
If no shared-parts is set, and shared is True, shared feature is not used:
If no ``shared-part-list`` is set, and ``shared`` is True, ``shared`` feature
is not used:
>>> write('buildout.cfg',
... """
... [buildout]
......@@ -1004,7 +1011,7 @@ If no shared-parts is set, and shared is True, shared feature is not used:
... url = file://%s/package-0.0.0.tar.gz
... shared = True
... """% src)
>>> print(system(buildout)) #doctest:+ELLIPSIS
Uninstalling package.
Uninstalling package-2.
......@@ -1013,10 +1020,11 @@ If no shared-parts is set, and shared is True, shared feature is not used:
building package
installing package
If shared-parts is set and shared is True, build package failed, the build directory is removed,
a build directory__compile__ is left for debugging.
Also a shell script with the environment variable is created, so that developer can try same build
process as the recipe tried.
If ``shared-part-list`` is set and shared is True, build package failed, the
build directory is removed, a build directory__compile__ is left for
debugging.
Also a shell script with the environment variable is created, so that
developer can try same build process as the recipe tried.
>>> _ = system('mv %s/package-0.0.0.tar.gz %s/package-0.0.0.tar.gz.bak' % (src, src))
>>> import tarfile
......@@ -1034,7 +1042,7 @@ process as the recipe tried.
... [buildout]
... newest = false
... parts = package
... shared-parts = %s
... shared-part-list = %s
...
... [package]
... recipe = slapos.recipe.cmmi
......@@ -1061,7 +1069,15 @@ process as the recipe tried.
export FOO="bar"
...
If shared-parts is set and shared is True, package will be installed in shared_part/package/a hash of the recipe's configuration options
If ``shared-part-list`` is set as an option in buildout section and
``shared`` is True, package will be installed in shared_part/package
and a hash of the recipe's configuration options.
There can be multiple path listed in ``shared-part-list``, the recipe
will look in each of these paths if package was already installed and
if not, it will install the package in the last entry the last entry
from the list of ``shared-part-list``.
>>> _ = system('mv %s/package-0.0.0.tar.gz.bak %s/package-0.0.0.tar.gz' % (src, src))
>>> print(system(buildout)) #doctest:+ELLIPSIS
package: shared directory /shared/package/FIRST_SHARED_PACKAGE_HASH set for package
......@@ -1073,7 +1089,8 @@ If shared-parts is set and shared is True, package will be installed in shared_p
building package
installing package
Do nothing if one package has been installed.
If package was already installed in any of the ``shared-part-list`` used, it will be
used instead of installing if one package has been installed.
>>> remove('.installed.cfg')
>>> write('buildout.cfg',
......@@ -1081,7 +1098,10 @@ Do nothing if one package has been installed.
... [buildout]
... newest = false
... parts = package
... shared-parts = %s
... shared-part-list =
... %s
... not/exists
... %s
...
... [package]
... recipe = slapos.recipe.cmmi
......@@ -1089,7 +1109,7 @@ Do nothing if one package has been installed.
... shared = True
... environment =
... FOO=bar
... """ % (shared_dir, src))
... """ % (shared_dir, another_shared_dir, src))
>>> print(system(buildout)) #doctest:+ELLIPSIS
package: shared directory /shared/package/FIRST_SHARED_PACKAGE_HASH set for package
Installing package.
......@@ -1102,7 +1122,7 @@ If options change, reinstall in different location:
... [buildout]
... newest = false
... parts = package
... shared-parts = %s
... shared-part-list = %s
...
... [package]
... recipe = slapos.recipe.cmmi
......
......@@ -41,26 +41,29 @@ class Recipe(object):
options.update(platform_options)
shared = ((options.get('shared', '').lower() == 'true') and
buildout['buildout'].get('shared-parts', None))
buildout['buildout'].get('shared-part-list', None))
if shared:
shared_part = buildout['buildout'].get('shared-parts', None)
shared = os.path.join(shared_part.strip().rstrip('/'), self.name)
if not os.path.exists(shared):
os.makedirs(shared)
self._signature = slapos.recipe.downloadunpacked.Signature('.slapos.recipe.cmmi.signature')
buildout_directory = buildout['buildout']['directory']
profile_base_location = options.get('_profile_base_location_', '')
for k, v in sorted(options.items()):
# Key not vary on profile base location
if profile_base_location:
v = v.replace(profile_base_location, '${:_profile_base_location_}')
self._signature.update(k, v)
shared = os.path.join(shared, self._signature.hexdigest())
log.info('shared directory %s set for %s', shared, self.name)
self._signature = slapos.recipe.downloadunpacked.Signature('.slapos.recipe.cmmi.signature')
buildout_directory = buildout['buildout']['directory']
profile_base_location = options.get('_profile_base_location_', '')
for k, v in sorted(options.items()):
# Key not vary on profile base location
if profile_base_location:
v = v.replace(profile_base_location, '${:_profile_base_location_}')
self._signature.update(k, v)
shared_parts = [part.strip().rstrip('/')
for part in buildout['buildout']['shared-part-list'].splitlines()
if part.strip()]
for shared in shared_parts:
shared = os.path.join(os.path.join(shared, self.name), self._signature.hexdigest())
if os.path.exists(shared):
break
else:
shared = os.path.join(os.path.join(shared_parts[-1], self.name), self._signature.hexdigest())
log.info('shared directory %s set for %s', shared, self.name)
else:
shared = ''
shared = ''
options['shared'] = shared
default_location = options['default-location'] = os.path.join(
......@@ -303,7 +306,7 @@ class Recipe(object):
# leftovers from a previous failed attempt, removing it.
log.warning('Removing already existing directory %s' % compile_dir)
shutil.rmtree(compile_dir)
os.mkdir(compile_dir)
os.makedirs(compile_dir)
try:
self.options.get('md5sum') # so that buildout does not complain "unused option md5sum"
opt = self.options.copy()
......
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