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 ...@@ -30,7 +30,7 @@ Supported options
Specify the path in which this package is shared by many other Specify the path in which this package is shared by many other
packages. packages.
Shared-parts should be defined in [buildout] section ``shared-part-list`` should be defined in ``[buildout]`` section
Shared option is True or False Shared option is True or False
The package will be installed on path/name/hash of options. The package will be installed on path/name/hash of options.
...@@ -987,12 +987,19 @@ Install shared package ...@@ -987,12 +987,19 @@ Install shared package
Use option ``shared`` to install a shared pacakge. Use option ``shared`` to install a shared pacakge.
>>> import os >>> 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') >>> shared_dir = join(os.path.dirname(__file__), 'shared')
>>> os.mkdir(shared_dir) >>> 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', >>> write('buildout.cfg',
... """ ... """
... [buildout] ... [buildout]
...@@ -1013,10 +1020,11 @@ If no shared-parts is set, and shared is True, shared feature is not used: ...@@ -1013,10 +1020,11 @@ If no shared-parts is set, and shared is True, shared feature is not used:
building package building package
installing package installing package
If shared-parts is set and shared is True, build package failed, the build directory is removed, If ``shared-part-list`` is set and shared is True, build package failed, the
a build directory__compile__ is left for debugging. build directory is removed, a build directory__compile__ is left for
Also a shell script with the environment variable is created, so that developer can try same build debugging.
process as the recipe tried. 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)) >>> _ = system('mv %s/package-0.0.0.tar.gz %s/package-0.0.0.tar.gz.bak' % (src, src))
>>> import tarfile >>> import tarfile
...@@ -1034,7 +1042,7 @@ process as the recipe tried. ...@@ -1034,7 +1042,7 @@ process as the recipe tried.
... [buildout] ... [buildout]
... newest = false ... newest = false
... parts = package ... parts = package
... shared-parts = %s ... shared-part-list = %s
... ...
... [package] ... [package]
... recipe = slapos.recipe.cmmi ... recipe = slapos.recipe.cmmi
...@@ -1061,7 +1069,15 @@ process as the recipe tried. ...@@ -1061,7 +1069,15 @@ process as the recipe tried.
export FOO="bar" 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)) >>> _ = system('mv %s/package-0.0.0.tar.gz.bak %s/package-0.0.0.tar.gz' % (src, src))
>>> print(system(buildout)) #doctest:+ELLIPSIS >>> print(system(buildout)) #doctest:+ELLIPSIS
package: shared directory /shared/package/FIRST_SHARED_PACKAGE_HASH set for package 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 ...@@ -1073,7 +1089,8 @@ If shared-parts is set and shared is True, package will be installed in shared_p
building package building package
installing 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') >>> remove('.installed.cfg')
>>> write('buildout.cfg', >>> write('buildout.cfg',
...@@ -1081,7 +1098,10 @@ Do nothing if one package has been installed. ...@@ -1081,7 +1098,10 @@ Do nothing if one package has been installed.
... [buildout] ... [buildout]
... newest = false ... newest = false
... parts = package ... parts = package
... shared-parts = %s ... shared-part-list =
... %s
... not/exists
... %s
... ...
... [package] ... [package]
... recipe = slapos.recipe.cmmi ... recipe = slapos.recipe.cmmi
...@@ -1089,7 +1109,7 @@ Do nothing if one package has been installed. ...@@ -1089,7 +1109,7 @@ Do nothing if one package has been installed.
... shared = True ... shared = True
... environment = ... environment =
... FOO=bar ... FOO=bar
... """ % (shared_dir, src)) ... """ % (shared_dir, another_shared_dir, src))
>>> print(system(buildout)) #doctest:+ELLIPSIS >>> print(system(buildout)) #doctest:+ELLIPSIS
package: shared directory /shared/package/FIRST_SHARED_PACKAGE_HASH set for package package: shared directory /shared/package/FIRST_SHARED_PACKAGE_HASH set for package
Installing package. Installing package.
...@@ -1102,7 +1122,7 @@ If options change, reinstall in different location: ...@@ -1102,7 +1122,7 @@ If options change, reinstall in different location:
... [buildout] ... [buildout]
... newest = false ... newest = false
... parts = package ... parts = package
... shared-parts = %s ... shared-part-list = %s
... ...
... [package] ... [package]
... recipe = slapos.recipe.cmmi ... recipe = slapos.recipe.cmmi
......
...@@ -41,13 +41,8 @@ class Recipe(object): ...@@ -41,13 +41,8 @@ class Recipe(object):
options.update(platform_options) options.update(platform_options)
shared = ((options.get('shared', '').lower() == 'true') and shared = ((options.get('shared', '').lower() == 'true') and
buildout['buildout'].get('shared-parts', None)) buildout['buildout'].get('shared-part-list', None))
if shared: 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') self._signature = slapos.recipe.downloadunpacked.Signature('.slapos.recipe.cmmi.signature')
buildout_directory = buildout['buildout']['directory'] buildout_directory = buildout['buildout']['directory']
profile_base_location = options.get('_profile_base_location_', '') profile_base_location = options.get('_profile_base_location_', '')
...@@ -57,7 +52,15 @@ class Recipe(object): ...@@ -57,7 +52,15 @@ class Recipe(object):
v = v.replace(profile_base_location, '${:_profile_base_location_}') v = v.replace(profile_base_location, '${:_profile_base_location_}')
self._signature.update(k, v) self._signature.update(k, v)
shared = os.path.join(shared, self._signature.hexdigest()) 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) log.info('shared directory %s set for %s', shared, self.name)
else: else:
shared = '' shared = ''
...@@ -303,7 +306,7 @@ class Recipe(object): ...@@ -303,7 +306,7 @@ class Recipe(object):
# leftovers from a previous failed attempt, removing it. # leftovers from a previous failed attempt, removing it.
log.warning('Removing already existing directory %s' % compile_dir) log.warning('Removing already existing directory %s' % compile_dir)
shutil.rmtree(compile_dir) shutil.rmtree(compile_dir)
os.mkdir(compile_dir) os.makedirs(compile_dir)
try: try:
self.options.get('md5sum') # so that buildout does not complain "unused option md5sum" self.options.get('md5sum') # so that buildout does not complain "unused option md5sum"
opt = self.options.copy() 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