Commit 90ccf8ca authored by Łukasz Nowak's avatar Łukasz Nowak

Initial import of slapos.tool.rebootstrap.

parent 893b8b14
2.4 (unreleased)
----------------
2.3 (2011-03-18)
----------------
- support case when rebootstrap parts directory already exists, to support
failed previous run [Łukasz Nowak]
2.2 (2011-01-24)
----------------
- support extensions in rebootstrap phase [Łukasz Nowak]
- rename to slapos.tool.reboostrap from slapos.rebootstrap [Łukasz Nowak]
2.1 (2010-12-02)
----------------
- use reboostrap.version prefix for generated files and directories instead
of suffix [Łukasz Nowak]
2.0 (2010-12-01)
----------------
- build python in "separated" environment to avoid reinstalling it in place,
backward incompatible with <=1.0 [Łukasz Nowak]
1.0 (2010-11-29)
----------------
- make possible to have newline in rebootstrap section [Łukasz Nowak]
0.4 (2010-11-04)
----------------
- re-run buildout while required part installation, to have all dependencies
installed correctly [Łukasz Nowak]
0.3 (2010-10-27)
----------------
- replace process while restarting buildout to have this process exit codes
and issues, as otherwise false positive exit code 0 might appear
[Łukasz Nowak]
0.2.1 (2010-10-15)
------------------
- fix documentation formatting
- fix documentation typos [Łukasz Nowak]
0.2 (unreleased)
-------------------
- Tested the egg. [Łukasz Nowak]
0.1 (2010-10-11)
----------------
- Initial version. [Łukasz Nowak]
include README.txt
include CHANGES.txt
include src/slapos/tool/rebootstrap/*.txt
Chicken and egg python zc.buildout extension
============================================
This extensions for zc.buildout is created to solve chicken and egg problem
while working with buildout and when some exact version of python, which is
provided by buildout shall be used to *execute* this buildout itself.
Usage
-----
Part to build python is required. By convention slapos.tool.rebootstrap will try to
find python executable in:
special.parts.directory/partname/bin/partname
But when needed python-path parameter can be used to point rebootstrap to find
python in:
special.parts.directory/partname/python-path
Add slapos.tool.rebootstrap to extensions and set rebooter-section to above section.
Use whatever python to bootstrap and run buildout. If reboot will detect that
sys.executable used to run buildout is different then executable provided in
python section it will try to find this executable. If it does not exists it
will install this section and then reinstall buildout using new python
executable. Later buildout run will continue using new python.
Because external buildout is used to provide buildout version parameter is
introduced to being able to upgrade not in place python part. This parameter
is required and becomes part of suffix.
Whenever developer-mode is set to true no cleanup will be done in case of
failure. Then user is responsible to cleanup directories.
Example profile and invocation
------------------------------
::
[buildout]
extensions = slapos.tool.rebootstrap
parts =
realrun
[rebootstrap]
section = slapospython
version = 1
[slapospython]
recipe = plone.recipe.command
stop-on-error = true
command = mkdir -p ${buildout:parts-directory}/${:__section_name__}/bin &&
cp -f /usr/bin/python ${:executable}
[realrun]
recipe = plone.recipe.command
command =
echo Running with python ${buildout:executable}
update-command = ${:command}
After bootstrapping and running this buildout it will print:
Running with python /path/to/buildout/parts.rebootstrap.1/slapospython/bin/slapospython
Running tests
-------------
Test for this package can be run as simple as:
$ python setup.py test
Please keep in mind that clean python environment is required -- the best one is
provided by buildout or virtualenv *WITHOUT* site packages.
[egg_info]
tag_build = .dev
tag_svn_revision = 1
from setuptools import setup, find_packages
version = '2.4'
name = "slapos.tool.rebootstrap"
setup(
name=name,
version=version,
description="A zc.buildout extension to solve chicken-and-egg problem of"\
" using python which is built by itself",
long_description=open("README.txt").read() + "\n\n" +
open("CHANGES.txt").read(),
classifiers=[
"Development Status :: 4 - Beta",
"Framework :: Buildout :: Extension",
"Intended Audience :: Developers",
"License :: OSI Approved :: Zope Public License",
"Programming Language :: Python",
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules",
],
entry_points={
'zc.buildout.extension': ['extension = %s:extension' % name],
},
license='ZPL 2.1',
include_package_data=True,
namespace_packages=['slapos'],
packages=find_packages('src'),
package_dir={'': 'src'},
zip_safe=True,
install_requires=[
'setuptools',
'zc.buildout'
],
tests_require=[
'zope.testing',
],
test_suite='%s.tests.test_suite' % name,
)
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
##############################################################################
#
# Copyright (c) 2010 ViFiB SARL and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import os
import shutil
import zc.buildout
import sys
import logging
import subprocess
def extension(buildout):
Rebootstrap(buildout)()
class Rebootstrap:
def __init__(self, buildout):
self.logger = logging.getLogger(__name__)
self.buildout = buildout
# fetch section of rebootstrap, obligatory
self.rebootstrap_section = buildout['rebootstrap']
# leave garbage? only in case of developer mode
self.developer_mode = self.rebootstrap_section.get('developer-mode',
'false') == 'true'
# fetch section to build python, obligatory
self.python_section = self.rebootstrap_section['section'].strip()
# fetch version of python build, obligatory
self.version = self.rebootstrap_section['version'].strip()
# usualy python will be try to found by convention in:
# prefixed-parts/part-name/bin/part-name
# but in case if part is non controlable it will be possible to
# find it as
# prefixed-parts/part-name/python-path
# where python-path is relative path to python interpreter
self.relative_python = self.rebootstrap_section.get('python-path', ''
).strip() or os.path.join('bin', self.python_section)
# query for currently running python
self.running_python = sys.executable
# generate rebootstrap.realname.version
self.prefix = 'rebootstrap.' + self.version + '.'
self.installed = '.' + self.prefix + 'installed.cfg'
self.parts_directory = os.path.join(self.buildout['buildout'][
'directory'], self.prefix + 'parts')
# query for wanted python, which is combination of suffixed parts
# and working recipe
self.wanted_python = os.path.join(self.parts_directory,
self.python_section, self.relative_python)
def __call__(self):
self.install_section()
self.reboot()
def reboot(self):
if self.running_python == self.wanted_python:
return
message = """
************ REBOOTSTRAP: IMPORTANT NOTICE ************
bin/buildout is being reinstalled right now, as new python:
%(wanted_python)s
is available, and buildout is using another python:
%(running_python)s
Buildout will be restarted automatically to have this change applied.
************ REBOOTSTRAP: IMPORTANT NOTICE ************
""" % dict(wanted_python=self.wanted_python,
running_python=self.running_python)
self.logger.info(message)
options = self.buildout['buildout']
specs = ['zc.buildout']
# XXX: A lot of below code is took from zc.buildout.buildout.py:_maybe_upgrade
# which is code duplication issue, but even if newer buildout with needed
# hooks will be released, this extension shall work on older ones
if zc.buildout.easy_install.is_distribute:
specs.append('distribute')
else:
specs.append('setuptools')
ws = zc.buildout.easy_install.install(
[
(spec + ' ' + options.get(spec+'-version', '')).strip()
for spec in specs
],
options['eggs-directory'],
links = options.get('find-links', '').split(),
index = options.get('index'),
path = [options['develop-eggs-directory']],
prefer_final=False,
executable=self.wanted_python
)
# the new dist is different, so we've upgraded.
# Update the scripts and return True
# Ideally the new version of buildout would get a chance to write the
# script. Not sure how to do that.
partsdir = os.path.join(options['parts-directory'], 'buildout')
if os.path.exists(partsdir):
# This is primarily for unit tests, in which .py files change too
# fast for Python to know to regenerate the .pyc/.pyo files.
shutil.rmtree(partsdir)
os.mkdir(partsdir)
script_initialization = ''
# (Honor the relative-paths option.)
relative_paths = options.get('relative-paths', 'false')
if relative_paths == 'true':
relative_paths = options['directory']
else:
assert relative_paths == 'false'
relative_paths = ''
zc.buildout.easy_install.sitepackage_safe_scripts(
options['bin-directory'], ws, self.wanted_python, partsdir,
reqs=['zc.buildout'], relative_paths=relative_paths,
include_site_packages=False,
script_initialization=script_initialization,
)
# Restart
args = map(zc.buildout.easy_install._safe_arg, sys.argv)
# We want to make sure that our new site.py is used for rerunning
# buildout, so we put the partsdir in PYTHONPATH for our restart.
# This overrides any set PYTHONPATH, but since we generally are
# trying to run with a completely "clean" python (only the standard
# library) then that should be fine.
env = os.environ.copy()
env['PYTHONPATH'] = partsdir
sys.stdout.flush()
os.execve(self.wanted_python, [self.wanted_python] + args, env)
def install_section(self):
try_install = False
try:
if not os.path.exists(self.parts_directory) \
or not os.path.exists(self.wanted_python):
try_install = True
self.logger.info('Installing section %r to provide %r in %r' % (
self.python_section, self.wanted_python, self.parts_directory))
args = map(zc.buildout.easy_install._safe_arg, sys.argv)
if 'install' in args:
args = args[:args.index('install')]
# remove rebootstrap extension, which is not needed in rebootstrap part
extension_list = self.buildout['buildout']['extensions'].split()
extension_list = [q.strip() for q in extension_list if q.strip() != \
__name__]
# rerun buildout with only neeeded section to reuse buildout
# ability to calcuate all dependency
args.extend([
# install only required section with dependencies
'buildout:parts=%s' % self.python_section,
# do not load extensions (even other ones)
'buildout:extensions=%s' % ' '.join(extension_list),
# create virutal python environment
'buildout:parts-directory=%s' % self.parts_directory,
'buildout:installed=%s' % self.installed,
])
self.logger.info('Rerunning buildout to install section %s with '
'arguments %r.'% (self.python_section, args))
process = subprocess.Popen(args)
process.wait()
if process.returncode != 0:
raise zc.buildout.UserError('Error during installing python '
'provision section.')
if not os.path.exists(self.wanted_python):
raise zc.buildout.UserError('Section %r directed to python executable:\n'
'%r\nUnfortunately even after installing this section executable was'
' not found.\nThis is section responsibility to provide python (eg. '
'by compiling it).' % (self.python_section, self.wanted_python))
except zc.buildout.UserError:
if try_install:
if not self.developer_mode:
if os.path.exists(self.parts_directory):
shutil.rmtree(self.parts_directory)
if os.path.exists(self.installed):
os.unlink(self.installed)
else:
self.logger.warning('Developer mode active.')
self.logger.warning('Directory %r and file %r are left for further '
'analysis.' % (self.parts_directory, self.installed))
self.logger.warning('Developer is responsible for removing those '
'directories.')
raise
>>> import sys
>>> mkdir(sample_buildout, 'recipes')
>>> write(sample_buildout, 'recipes', 'setup.py',
... """
... from setuptools import setup
...
... setup(
... name = "recipes",
... entry_points = {'zc.buildout':[
... 'pyinstall = pyinstall:Pyinstall',
... 'pyshow = pyshow:Pyshow',
... ]},
... )
... """)
>>> write(sample_buildout, 'recipes', 'README.txt', " ")
>>> write(sample_buildout, 'recipes', 'pyinstall.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyinstall:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
... self.destination = os.path.join(buildout['buildout'][
... 'parts-directory'], self.options.get('python', name))
...
... def install(self):
... for d in [self.destination, os.path.join(self.destination, 'bin')]:
... if not os.path.exists(d):
... os.mkdir(d)
... python = os.path.join(self.destination, 'bin', self.name)
... if not os.path.exists(python):
... shutil.copy(sys.executable, python)
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'recipes', 'pyshow.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyshow:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
...
... def install(self):
... print 'Running with:', sys.executable
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... parts =
... """)
>>> print system(buildout),
Develop: '/sample-buildout/recipes'
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... extensions = slapos.tool.rebootstrap
...
... parts =
... realrun
...
... [rebootstrap]
... section =
... installpython
... version =
... 1
...
... [installpython]
... recipe = recipes:pyinstall
...
... [realrun]
... recipe = recipes:pyshow
... """ % dict(syspython=sys.executable))
>>> print system(buildout),
slapos.tool.rebootstrap: Installing section 'installpython' to provide '/sample-buildout/rebootstrap.1.parts/installpython/bin/installpython' in '/sample-buildout/rebootstrap.1.parts'
slapos.tool.rebootstrap: Rerunning buildout to install section installpython with arguments ['/sample-buildout/bin/buildout', 'buildout:parts=installpython', 'buildout:extensions=', '/sample-buildout/rebootstrap.1.parts', 'buildout:installed=.rebootstrap.1.installed.cfg'].
Creating directory '/sample-buildout/rebootstrap.1.parts'.
Develop: '/sample-buildout/recipes'
Installing installpython.
slapos.tool.rebootstrap:
************ REBOOTSTRAP: IMPORTANT NOTICE ************
bin/buildout is being reinstalled right now, as new python:
/sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
is available, and buildout is using another python:
/system_python
Buildout will be restarted automatically to have this change applied.
************ REBOOTSTRAP: IMPORTANT NOTICE ************
<BLANKLINE>
Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/recipes'
Installing realrun.
Running with: /sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
>>> import sys
>>> mkdir(sample_buildout, 'recipes')
>>> write(sample_buildout, 'recipes', 'setup.py',
... """
... from setuptools import setup
...
... setup(
... name = "recipes",
... entry_points = {'zc.buildout':[
... 'pyinstall = pyinstall:Pyinstall',
... 'pyshow = pyshow:Pyshow',
... ],
... 'zc.buildout.extension': ['ext = extension:extension'],},
... )
... """)
>>> write(sample_buildout, 'recipes', 'README.txt', " ")
>>> write(sample_buildout, 'recipes', 'extension.py',
... """
... def extension(buildout):
... print 'Special extension run'
... """)
>>> write(sample_buildout, 'recipes', 'pyinstall.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyinstall:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
... self.destination = os.path.join(buildout['buildout'][
... 'parts-directory'], self.options.get('python', name))
...
... def install(self):
... for d in [self.destination, os.path.join(self.destination, 'bin')]:
... if not os.path.exists(d):
... os.mkdir(d)
... python = os.path.join(self.destination, 'bin', self.name)
... if not os.path.exists(python):
... shutil.copy(sys.executable, python)
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'recipes', 'pyshow.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyshow:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
...
... def install(self):
... print 'Running with:', sys.executable
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... parts =
... """)
>>> print system(buildout),
Develop: '/sample-buildout/recipes'
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... extensions = slapos.tool.rebootstrap recipes
...
... parts =
... realrun
...
... [rebootstrap]
... section =
... installpython
... version =
... 1
...
... [installpython]
... recipe = recipes:pyinstall
...
... [realrun]
... recipe = recipes:pyshow
... """ % dict(syspython=sys.executable))
>>> print system(buildout),
slapos.tool.rebootstrap: Installing section 'installpython' to provide '/sample-buildout/rebootstrap.1.parts/installpython/bin/installpython' in '/sample-buildout/rebootstrap.1.parts'
slapos.tool.rebootstrap: Rerunning buildout to install section installpython with arguments ['/sample-buildout/bin/buildout', 'buildout:parts=installpython', 'buildout:extensions=recipes', '/sample-buildout/rebootstrap.1.parts', 'buildout:installed=.rebootstrap.1.installed.cfg'].
Special extension run
Creating directory '/sample-buildout/rebootstrap.1.parts'.
Develop: '/sample-buildout/recipes'
Installing installpython.
slapos.tool.rebootstrap:
************ REBOOTSTRAP: IMPORTANT NOTICE ************
bin/buildout is being reinstalled right now, as new python:
/sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
is available, and buildout is using another python:
/system_python
Buildout will be restarted automatically to have this change applied.
************ REBOOTSTRAP: IMPORTANT NOTICE ************
<BLANKLINE>
Generated script '/sample-buildout/bin/buildout'.
Special extension run
Develop: '/sample-buildout/recipes'
Installing realrun.
Running with: /sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
>>> import sys
>>> mkdir(sample_buildout, 'recipes')
>>> write(sample_buildout, 'recipes', 'setup.py',
... """
... from setuptools import setup
...
... setup(
... name = "recipes",
... entry_points = {'zc.buildout':[
... 'pyinstall = pyinstall:Pyinstall',
... 'pyshow = pyshow:Pyshow',
... ]},
... )
... """)
>>> write(sample_buildout, 'recipes', 'README.txt', " ")
>>> write(sample_buildout, 'recipes', 'pyinstall.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyinstall:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
... self.destination = os.path.join(buildout['buildout'][
... 'parts-directory'], self.options.get('python', name))
...
... def install(self):
... for d in [self.destination, os.path.join(self.destination, 'bin')]:
... if not os.path.exists(d):
... os.mkdir(d)
... python = os.path.join(self.destination, 'bin', self.name)
... if not os.path.exists(python):
... shutil.copy(sys.executable, python)
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'recipes', 'pyshow.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyshow:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
...
... def install(self):
... print 'Running with:', sys.executable
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... parts =
... """)
>>> print system(buildout),
Develop: '/sample-buildout/recipes'
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... extensions = slapos.tool.rebootstrap
...
... parts =
... realrun
...
... [rebootstrap]
... section =
... installpython
... version =
... 1
...
... [installpython]
... recipe = recipes:pyinstall
...
... [realrun]
... recipe = recipes:pyshow
... """ % dict(syspython=sys.executable))
>>> import os
>>> os.mkdir('rebootstrap.1.parts')
>>> print system(buildout),
slapos.tool.rebootstrap: Installing section 'installpython' to provide '/sample-buildout/rebootstrap.1.parts/installpython/bin/installpython' in '/sample-buildout/rebootstrap.1.parts'
slapos.tool.rebootstrap: Rerunning buildout to install section installpython with arguments ['/sample-buildout/bin/buildout', 'buildout:parts=installpython', 'buildout:extensions=', '/sample-buildout/rebootstrap.1.parts', 'buildout:installed=.rebootstrap.1.installed.cfg'].
Develop: '/sample-buildout/recipes'
Installing installpython.
slapos.tool.rebootstrap:
************ REBOOTSTRAP: IMPORTANT NOTICE ************
bin/buildout is being reinstalled right now, as new python:
/sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
is available, and buildout is using another python:
/system_python
Buildout will be restarted automatically to have this change applied.
************ REBOOTSTRAP: IMPORTANT NOTICE ************
<BLANKLINE>
Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/recipes'
Installing realrun.
Running with: /sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
##############################################################################
#
# Copyright (c) 2010 ViFiB SARL and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
from zope.testing import renormalizing
import doctest
import pkg_resources
import re
import sys
import unittest
import zc.buildout
import zc.buildout.testing
import zc.buildout.tests
def setUp(test):
zc.buildout.testing.buildoutSetUp(test)
zc.buildout.testing.install_develop('slapos.tool.rebootstrap', test)
def test_suite():
# Note: Doctests are used, as this is the good way to test zc.buildout based
# applications. And zc.buildout.testing.buildoutSetUp does *NOT* support
# non-doctest suites
kwargs = dict(setUp=setUp,
tearDown=zc.buildout.testing.buildoutTearDown,
checker=renormalizing.RENormalizing([
(re.compile('--prefix=\S+sample-buildout'),
'--prefix=/sample_buildout'),
(re.compile('\s/\S+sample-buildout'),
' /sample_buildout'),
(re.compile(sys.executable),
'/system_python'),
zc.buildout.testing.normalize_path,
]),
)
test_list = []
for text in pkg_resources.resource_listdir(__name__, '.'):
if text.endswith('.txt'):
test_list.append(doctest.DocFileSuite(text, **kwargs))
suite = unittest.TestSuite(test_list)
return suite
>>> import sys
>>> mkdir(sample_buildout, 'recipes')
>>> write(sample_buildout, 'recipes', 'setup.py',
... """
... from setuptools import setup
...
... setup(
... name = "recipes",
... entry_points = {'zc.buildout':[
... 'pyinstall = pyinstall:Pyinstall',
... 'pyshow = pyshow:Pyshow',
... ]},
... )
... """)
>>> write(sample_buildout, 'recipes', 'README.txt', " ")
>>> write(sample_buildout, 'recipes', 'pyinstall.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyinstall:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
... self.destination = os.path.join(buildout['buildout'][
... 'parts-directory'], self.options.get('python', name))
...
... def install(self):
... for d in [self.destination, os.path.join(self.destination, 'bin')]:
... if not os.path.exists(d):
... os.mkdir(d)
... python = os.path.join(self.destination, 'bin', self.name)
... if not os.path.exists(python):
... shutil.copy(sys.executable, python)
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'recipes', 'pyshow.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyshow:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
...
... def install(self):
... print 'Running with:', sys.executable
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... parts =
... """)
>>> print system(buildout),
Develop: '/sample-buildout/recipes'
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... extensions = slapos.tool.rebootstrap
...
... parts =
... realrun
...
... [rebootstrap]
... section =
... installpython
... version =
... 1
...
... [installpython]
... recipe = recipes:pyinstall
...
... [realrun]
... recipe = recipes:pyshow
... """ % dict(syspython=sys.executable))
>>> print system(buildout),
slapos.tool.rebootstrap: Installing section 'installpython' to provide '/sample-buildout/rebootstrap.1.parts/installpython/bin/installpython' in '/sample-buildout/rebootstrap.1.parts'
slapos.tool.rebootstrap: Rerunning buildout to install section installpython with arguments ['/sample-buildout/bin/buildout', 'buildout:parts=installpython', 'buildout:extensions=', '/sample-buildout/rebootstrap.1.parts', 'buildout:installed=.rebootstrap.1.installed.cfg'].
Creating directory '/sample-buildout/rebootstrap.1.parts'.
Develop: '/sample-buildout/recipes'
Installing installpython.
slapos.tool.rebootstrap:
************ REBOOTSTRAP: IMPORTANT NOTICE ************
bin/buildout is being reinstalled right now, as new python:
/sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
is available, and buildout is using another python:
/system_python
Buildout will be restarted automatically to have this change applied.
************ REBOOTSTRAP: IMPORTANT NOTICE ************
<BLANKLINE>
Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/recipes'
Installing realrun.
Running with: /sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... extensions = slapos.tool.rebootstrap
...
... parts =
... realrun
...
... [rebootstrap]
... section =
... installpython
... version =
... 2
...
... [installpython]
... recipe = recipes:pyinstall
...
... [realrun]
... recipe = recipes:pyshow
... """ % dict(syspython=sys.executable))
>>> print system(buildout),
slapos.tool.rebootstrap: Installing section 'installpython' to provide '/sample-buildout/rebootstrap.2.parts/installpython/bin/installpython' in '/sample-buildout/rebootstrap.2.parts'
slapos.tool.rebootstrap: Rerunning buildout to install section installpython with arguments ['/sample-buildout/bin/buildout', 'buildout:parts=installpython', 'buildout:extensions=', '/sample-buildout/rebootstrap.2.parts', 'buildout:installed=.rebootstrap.2.installed.cfg'].
Creating directory '/sample-buildout/rebootstrap.2.parts'.
Develop: '/sample-buildout/recipes'
Installing installpython.
slapos.tool.rebootstrap:
************ REBOOTSTRAP: IMPORTANT NOTICE ************
bin/buildout is being reinstalled right now, as new python:
/sample_buildout/rebootstrap.2.parts/installpython/bin/installpython
is available, and buildout is using another python:
/sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
Buildout will be restarted automatically to have this change applied.
************ REBOOTSTRAP: IMPORTANT NOTICE ************
<BLANKLINE>
Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/recipes'
Updating realrun.
Running with: /sample_buildout/rebootstrap.2.parts/installpython/bin/installpython
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... extensions = slapos.tool.rebootstrap
...
... parts =
... realrun
...
... [rebootstrap]
... section =
... installpython
... version =
... 1
...
... [installpython]
... recipe = recipes:pyinstall
...
... [realrun]
... recipe = recipes:pyshow
... """ % dict(syspython=sys.executable))
>>> print system(buildout),
slapos.tool.rebootstrap:
************ REBOOTSTRAP: IMPORTANT NOTICE ************
bin/buildout is being reinstalled right now, as new python:
/sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
is available, and buildout is using another python:
/sample_buildout/rebootstrap.2.parts/installpython/bin/installpython
Buildout will be restarted automatically to have this change applied.
************ REBOOTSTRAP: IMPORTANT NOTICE ************
<BLANKLINE>
Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/recipes'
Updating realrun.
Running with: /sample_buildout/rebootstrap.1.parts/installpython/bin/installpython
>>> import sys
>>> mkdir(sample_buildout, 'recipes')
>>> write(sample_buildout, 'recipes', 'setup.py',
... """
... from setuptools import setup
...
... setup(
... name = "recipes",
... entry_points = {'zc.buildout':[
... 'pyinstall = pyinstall:Pyinstall',
... 'pyshow = pyshow:Pyshow',
... ]},
... )
... """)
>>> write(sample_buildout, 'recipes', 'README.txt', " ")
>>> write(sample_buildout, 'recipes', 'pyinstall.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyinstall:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
... self.destination = os.path.join(buildout['buildout'][
... 'parts-directory'], name)
...
... def install(self):
... for d in [self.destination, os.path.join(self.destination, 'bin')]:
... if not os.path.exists(d):
... os.mkdir(d)
... python = self.options.get('python', os.path.join('bin', self.name))
... python = os.path.join(self.destination, python)
... if not os.path.exists(python):
... shutil.copy(sys.executable, python)
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'recipes', 'pyshow.py',
... """
... import os, zc.buildout, shutil, sys
...
... class Pyshow:
...
... def __init__(self, buildout, name, options):
... self.name, self.options = name, options
...
... def install(self):
... print 'Running with:', sys.executable
... return []
...
... update = install
... """)
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... parts =
... """)
>>> print system(buildout),
Develop: '/sample-buildout/recipes'
>>> write(sample_buildout, 'buildout.cfg',
... """
... [buildout]
... develop = recipes
... extensions = slapos.tool.rebootstrap
...
... parts =
... realrun
...
... [rebootstrap]
... section =
... installpython
... version =
... 1
... python-path =
... anotherpython
...
... [installpython]
... recipe = recipes:pyinstall
... python = anotherpython
...
... [realrun]
... recipe = recipes:pyshow
... """ % dict(syspython=sys.executable))
>>> print system(buildout),
slapos.tool.rebootstrap: Installing section 'installpython' to provide '/sample-buildout/rebootstrap.1.parts/installpython/anotherpython' in '/sample-buildout/rebootstrap.1.parts'
slapos.tool.rebootstrap: Rerunning buildout to install section installpython with arguments ['/sample-buildout/bin/buildout', 'buildout:parts=installpython', 'buildout:extensions=', '/sample-buildout/rebootstrap.1.parts', 'buildout:installed=.rebootstrap.1.installed.cfg'].
Creating directory '/sample-buildout/rebootstrap.1.parts'.
Develop: '/sample-buildout/recipes'
Installing installpython.
slapos.tool.rebootstrap:
************ REBOOTSTRAP: IMPORTANT NOTICE ************
bin/buildout is being reinstalled right now, as new python:
/sample_buildout/rebootstrap.1.parts/installpython/anotherpython
is available, and buildout is using another python:
/system_python
Buildout will be restarted automatically to have this change applied.
************ REBOOTSTRAP: IMPORTANT NOTICE ************
<BLANKLINE>
Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/recipes'
Installing realrun.
Running with: /sample_buildout/rebootstrap.1.parts/installpython/anotherpython
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