[Checkins] SVN: zc.buildout/trunk/s Added a self-updating feature,
so buildouts now update themselves.
Jim Fulton
jim at zope.com
Fri Sep 1 19:54:30 EDT 2006
Log message for revision 69924:
Added a self-updating feature, so buildouts now update themselves.
Changed:
U zc.buildout/trunk/setup.py
U zc.buildout/trunk/src/zc/buildout/buildout.py
U zc.buildout/trunk/src/zc/buildout/buildout.txt
U zc.buildout/trunk/src/zc/buildout/tests.py
A zc.buildout/trunk/src/zc/buildout/update.txt
-=-
Modified: zc.buildout/trunk/setup.py
===================================================================
--- zc.buildout/trunk/setup.py 2006-09-01 23:54:27 UTC (rev 69923)
+++ zc.buildout/trunk/setup.py 2006-09-01 23:54:29 UTC (rev 69924)
@@ -23,4 +23,5 @@
entry_points = {'console_scripts':
['buildout = %s.buildout:main' % name]},
dependency_links = ['http://download.zope.org/distribution/'],
+ zip_safe=False,
)
Modified: zc.buildout/trunk/src/zc/buildout/buildout.py
===================================================================
--- zc.buildout/trunk/src/zc/buildout/buildout.py 2006-09-01 23:54:27 UTC (rev 69923)
+++ zc.buildout/trunk/src/zc/buildout/buildout.py 2006-09-01 23:54:29 UTC (rev 69924)
@@ -25,7 +25,6 @@
import sys
import ConfigParser
-import zc.buildout.easy_install
import pkg_resources
import zc.buildout.easy_install
@@ -245,6 +244,9 @@
# for eggs:
sys.path.insert(0, self['buildout']['develop-eggs-directory'])
+ # Check for updates. This could cause the process to be rstarted
+ self._maybe_upgrade()
+
# Build develop eggs
self._develop()
@@ -524,6 +526,54 @@
_save_options(section, self[section], sys.stdout)
print
+ def _maybe_upgrade(self):
+ # See if buildout or setuptools need to be upgraded.
+ # If they do, do the upgrade and return true.
+ # Otherwise, return False.
+ ws = zc.buildout.easy_install.install(
+ [
+ (spec + ' ' + self['buildout'].get(spec+'-version', '')).strip()
+ for spec in ('zc.buildout', 'setuptools')
+ ],
+ self['buildout']['eggs-directory'],
+ links = self['buildout'].get('find-links', '').split(),
+ index = self['buildout'].get('index'),
+ path = [self['buildout']['develop-eggs-directory']],
+ )
+
+ upgraded = []
+ for project in 'zc.buildout', 'setuptools':
+ req = pkg_resources.Requirement.parse(project)
+ if ws.find(req) != pkg_resources.working_set.find(req):
+ upgraded.append(ws.find(req))
+
+ if not upgraded:
+ return
+
+ self._logger.info("Upgraded: %s, restarting.",
+ ", ".join([("%s version %s"
+ % (dist.project_name, dist.version)
+ )
+ for dist in upgraded
+ ]
+ ),
+ )
+
+ # the new dist is different, so we've upgraded.
+ # Update the scripts and return True
+ zc.buildout.easy_install.scripts(
+ ['zc.buildout'], ws, sys.executable,
+ self['buildout']['bin-directory'],
+ )
+
+ # Restart
+ args = map(zc.buildout.easy_install._safe_arg, sys.argv)
+ if not __debug__:
+ args.insert(0, '-O')
+ args.insert(0, sys.executable)
+ sys.exit(os.spawnv(os.P_WAIT, sys.executable, args))
+
+
_spacey_nl = re.compile('[ \t\r\f\v]*\n[ \t\r\f\v\n]*'
'|'
'^[ \t\r\f\v]+'
Modified: zc.buildout/trunk/src/zc/buildout/buildout.txt
===================================================================
--- zc.buildout/trunk/src/zc/buildout/buildout.txt 2006-09-01 23:54:27 UTC (rev 69923)
+++ zc.buildout/trunk/src/zc/buildout/buildout.txt 2006-09-01 23:54:29 UTC (rev 69924)
@@ -1103,6 +1103,10 @@
python = buildout
verbosity = 20
<BLANKLINE>
+ zc.buildout.easy_install: Installing ['zc.buildout', 'setuptools']
+ zc.buildout.easy_install: We have a develop egg for zc.buildout
+ zc.buildout.easy_install: We have the best distributon that satisfies
+ setuptools
All of these options can be overridden by configuration files or by
command-line assignments. We've discussed most of these options
Modified: zc.buildout/trunk/src/zc/buildout/tests.py
===================================================================
--- zc.buildout/trunk/src/zc/buildout/tests.py 2006-09-01 23:54:27 UTC (rev 69923)
+++ zc.buildout/trunk/src/zc/buildout/tests.py 2006-09-01 23:54:29 UTC (rev 69924)
@@ -16,9 +16,10 @@
$Id$
"""
-import os, re, shutil, sys, unittest
+import os, re, shutil, sys, unittest, zipfile
from zope.testing import doctest, renormalizing
-import zc.buildout.testing
+import pkg_resources
+import zc.buildout.testing, zc.buildout.easy_install
os_path_sep = os.path.sep
if os_path_sep == '\\':
@@ -321,6 +322,75 @@
return result
+
+
+egg_parse = re.compile('([0-9a-zA-Z_.]+)-([0-9a-zA-Z_.]+)-py(\d[.]\d).egg$'
+ ).match
+def makeNewRelease(project, ws, dest):
+ dist = ws.find(pkg_resources.Requirement.parse(project))
+ eggname, oldver, pyver = egg_parse(
+ os.path.basename(dist.location)
+ ).groups()
+ dest = os.path.join(dest, "%s-99.99-py%s.egg" % (eggname, pyver))
+ if os.path.isfile(dist.location):
+ shutil.copy(dist.location, dest)
+ zip = zipfile.ZipFile(dest, 'a')
+ zip.writestr(
+ 'EGG-INFO/PKG-INFO',
+ zip.read('EGG-INFO/PKG-INFO').replace("Version: %s" % oldver,
+ "Version: 99.99")
+ )
+ zip.close()
+ else:
+ shutil.copy(dist.location, dest)
+ info_path = os.path.join(dest, 'EGG-INFO', 'PKG-INFO')
+ info = open(info_path).read().replace("Version: %s" % oldver,
+ "Version: 99.99")
+ open(info_path, 'w').write(info)
+
+
+def updateSetup(test):
+ zc.buildout.testing.buildoutSetUp(test)
+ test.globs['new_releases'] = new_releases = test.globs['mkdtemp']()
+ sample_buildout = test.globs['sample_buildout']
+ eggs = os.path.join(sample_buildout, 'eggs')
+
+ # If the zc.buildout dist is a develo dist, convert it to a
+ # regular egg in the sample buildout
+ req = pkg_resources.Requirement.parse('zc.buildout')
+ dist = pkg_resources.working_set.find(req)
+ if dist.precedence == pkg_resources.DEVELOP_DIST:
+ # We have a develop egg, create a real egg for it:
+ here = os.getcwd()
+ os.chdir(os.path.dirname(dist.location))
+ assert os.spawnle(
+ os.P_WAIT, sys.executable, sys.executable,
+ os.path.join(os.path.dirname(dist.location), 'setup.py'),
+ '-q', 'bdist_egg', '-d', eggs,
+ dict(os.environ,
+ PYTHONPATH=pkg_resources.working_set.find(
+ pkg_resources.Requirement.parse('setuptools')
+ ).location,
+ ),
+ ) == 0
+ os.chdir(here)
+ os.remove(os.path.join(eggs, 'zc.buildout.egg-link'))
+
+ # Rebuild the buildout script
+ ws = pkg_resources.WorkingSet([eggs])
+ ws.require('zc.buildout')
+ zc.buildout.easy_install.scripts(
+ ['zc.buildout'], ws, sys.executable,
+ os.path.join(sample_buildout, 'bin'))
+ else:
+ ws = pkg_resources.working_set
+
+ # now let's make the new releases
+ makeNewRelease('zc.buildout', ws, new_releases)
+ makeNewRelease('setuptools', ws, new_releases)
+
+ os.mkdir(os.path.join(new_releases, 'zc.buildout'))
+ os.mkdir(os.path.join(new_releases, 'setuptools'))
def test_suite():
return unittest.TestSuite((
@@ -345,6 +415,17 @@
(re.compile("(\w)%s(\w)" % os_path_sep), r"\1/\2"),
])
),
+
+ doctest.DocFileSuite(
+ 'update.txt',
+ setUp=updateSetup,
+ tearDown=zc.buildout.testing.buildoutTearDown,
+ checker=renormalizing.RENormalizing([
+ (re.compile('#!\S+python\S+'), '#!python'),
+ (re.compile('\S+sample-(\w+)'), r'/sample-\1'),
+ (re.compile('-py\d[.]\d.egg'), r'-py2.3.egg'),
+ ])
+ ),
doctest.DocFileSuite(
'easy_install.txt',
Added: zc.buildout/trunk/src/zc/buildout/update.txt
===================================================================
--- zc.buildout/trunk/src/zc/buildout/update.txt 2006-09-01 23:54:27 UTC (rev 69923)
+++ zc.buildout/trunk/src/zc/buildout/update.txt 2006-09-01 23:54:29 UTC (rev 69924)
@@ -0,0 +1,84 @@
+Automatic Buildout Updates
+==========================
+
+When a buildout is run, one of the first steps performed is to check
+for updates to either zc.buildout or setuptools. To demonstrate this,
+we've creates some "new releases" of buildout and setuptools in a
+new_releases folder:
+
+ >>> ls(new_releases)
+ d setuptools
+ - setuptools-99.99-py2.3.egg
+ d zc.buildout
+ - zc.buildout-99.99-py2.3.egg
+
+Let's update the sample buildout.cfg to look in this area:
+
+ >>> write(sample_buildout, 'buildout.cfg',
+ ... """
+ ... [buildout]
+ ... find-links = %(new_releases)s
+ ... index = %(new_releases)s
+ ... parts = show-versions
+ ... develop = showversions
+ ...
+ ... [show-versions]
+ ... recipe = showversions
+ ... """ % dict(new_releases=new_releases))
+
+We'll also include a recipe that echos the version sof setuptools and
+zc.buildout used:
+
+ >>> mkdir(sample_buildout, 'showversions')
+
+ >>> write(sample_buildout, 'showversions', 'showversions.py',
+ ... """
+ ... import pkg_resources
+ ...
+ ... class Recipe:
+ ...
+ ... def __init__(self, buildout, name, options):
+ ... pass
+ ...
+ ... def install(self):
+ ... for project in 'zc.buildout', 'setuptools':
+ ... req = pkg_resources.Requirement.parse(project)
+ ... print project, pkg_resources.working_set.find(req).version
+ ... """)
+
+
+ >>> write(sample_buildout, 'showversions', 'setup.py',
+ ... """
+ ... from setuptools import setup
+ ...
+ ... setup(
+ ... name = "showversions",
+ ... entry_points = {'zc.buildout': ['default = showversions:Recipe']},
+ ... )
+ ... """)
+
+Now if we run the buildout, the buildout will upgrade itself to the
+new versions found in new releases:
+
+ >>> import os
+ >>> os.chdir(sample_buildout)
+ >>> buildout = os.path.join(sample_buildout, 'bin', 'buildout')
+ >>> print system(buildout),
+ zc.buildout 99.99
+ setuptools 99.99
+
+Our buildout script has been updated to use the new eggs:
+
+ >>> cat(sample_buildout, 'bin', 'buildout')
+ #!/usr/local/bin/python2.3
+ <BLANKLINE>
+ import sys
+ sys.path[0:0] = [
+ '/tmp/tmpc4avO6sample-buildout/eggs/zc.buildout-99.99-py2.3.egg',
+ '/tmp/tmpc4avO6sample-buildout/eggs/setuptools-99.99-py2.3.egg'
+ ]
+ <BLANKLINE>
+ import zc.buildout.buildout
+ <BLANKLINE>
+ if __name__ == '__main__':
+ zc.buildout.buildout.main()
Property changes on: zc.buildout/trunk/src/zc/buildout/update.txt
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Checkins
mailing list