[Checkins] SVN: zc.buildout/trunk/ Features:
Jim Fulton
jim at zope.com
Tue Mar 6 11:03:00 EST 2007
Log message for revision 73006:
Features:
- The easy_install module install and build functions now accept a
versions argument that supplied to mapping from project name to
version numbers. This can be used to fix version numbers for
required distributions and their depenencies.
When a version isn't fixed, using either a versions option or using
a fixed version number in a requirement, then a debug log message is
emitted indicating the version picked. This is useful for setting
versions options.
- Added a remove testing helper function that removes files or directories.
Changed:
U zc.buildout/trunk/CHANGES.txt
U zc.buildout/trunk/src/zc/buildout/buildout.txt
U zc.buildout/trunk/src/zc/buildout/easy_install.py
U zc.buildout/trunk/src/zc/buildout/easy_install.txt
U zc.buildout/trunk/src/zc/buildout/testing.py
U zc.buildout/trunk/src/zc/buildout/testing.txt
U zc.buildout/trunk/src/zc/buildout/tests.py
-=-
Modified: zc.buildout/trunk/CHANGES.txt
===================================================================
--- zc.buildout/trunk/CHANGES.txt 2007-03-06 11:35:37 UTC (rev 73005)
+++ zc.buildout/trunk/CHANGES.txt 2007-03-06 16:02:59 UTC (rev 73006)
@@ -23,10 +23,22 @@
Feature Changes
---------------
+- The easy_install module install and build functions now accept a
+ versions argument that supplied to mapping from project name to
+ version numbers. This can be used to fix version numbers for
+ required distributions and their depenencies.
+
+ When a version isn't fixed, using either a versions option or using
+ a fixed version number in a requirement, then a debug log message is
+ emitted indicating the version picked. This is useful for setting
+ versions options.
+
- Adjusted the output for verbosity levels. Using a single -v option
no longer causes voluminous setuptools output. Uisng -vv and -vvv
now triggers extra setuptools output.
+- Added a remove testing helper function that removes files or directories.
+
1.0.0b20 (2007-02-08)
=====================
Modified: zc.buildout/trunk/src/zc/buildout/buildout.txt
===================================================================
--- zc.buildout/trunk/src/zc/buildout/buildout.txt 2007-03-06 11:35:37 UTC (rev 73005)
+++ zc.buildout/trunk/src/zc/buildout/buildout.txt 2007-03-06 16:02:59 UTC (rev 73006)
@@ -1598,8 +1598,10 @@
>>> print system(buildout+' -v'),
zc.buildout.easy_install: Installing ['zc.buildout', 'setuptools']
zc.buildout.easy_install: We have a develop egg for zc.buildout
+ zc.buildout.easy_install: Picked version for zc.buildout = 1.0.0
zc.buildout.easy_install: We have the best distribution that satisfies
setuptools
+ zc.buildout.easy_install: Picked version for setuptools = 0.6
<BLANKLINE>
Configuration data:
[buildout]
Modified: zc.buildout/trunk/src/zc/buildout/easy_install.py
===================================================================
--- zc.buildout/trunk/src/zc/buildout/easy_install.py 2007-03-06 11:35:37 UTC (rev 73005)
+++ zc.buildout/trunk/src/zc/buildout/easy_install.py 2007-03-06 16:02:59 UTC (rev 73006)
@@ -45,6 +45,10 @@
pkg_resources.Requirement.parse('zc.buildout')).location,
]
+class IncompatibleVersionError(zc.buildout.UserError):
+ """A specified version is incompatible with a given requirement.
+ """
+
_versions = {sys.executable: '%d.%d' % sys.version_info[:2]}
def _get_version(executable):
try:
@@ -109,6 +113,7 @@
always_unzip=False,
path=None,
newest=True,
+ versions=None,
):
self._dest = dest
self._links = list(links)
@@ -123,6 +128,7 @@
self._env = pkg_resources.Environment(path,
python=_get_version(executable))
self._index = _get_index(executable, index, links)
+ self._versions = versions or {}
def _satisfied(self, req):
dists = [dist for dist in self._env[req.project_name] if dist in req]
@@ -246,7 +252,7 @@
if self._dest is not None:
logger.info("Getting new distribution for %s", requirement)
- # Retrieve the dist:
+ # Retrieve the dist:grokonepage
index = self._index
dist = index.obtain(requirement)
if dist is None:
@@ -336,6 +342,13 @@
self._index = _get_index(self._executable,
self._index_url, self._links)
+ # Check whether we picked a version and, if we did, report it:
+ if not (
+ len(requirement.specs) == 1 and requirement.specs[0][0] == '=='
+ ):
+ logger.debug('Picked version for %s = %s',
+ dist.project_name, dist.version)
+
return dist
def _maybe_add_setuptools(self, ws, dist):
@@ -351,12 +364,27 @@
"uses namespace packages but the distribution "
"does not require setuptools.",
dist)
- requirement = pkg_resources.Requirement.parse('setuptools')
+ requirement = self._constrain(
+ pkg_resources.Requirement.parse('setuptools')
+ )
if ws.find(requirement) is None:
dist = self._get_dist(requirement, ws, False)
ws.add(dist)
+ def _constrain(self, requirement):
+ version = self._versions.get(requirement.project_name)
+ if version:
+ if version not in requirement:
+ logger.error("The version, %s, is not consistent with the "
+ "requirement, %s", version, requirement)
+ raise IncompatibleVersionError("Bad version", version)
+
+ requirement = pkg_resources.Requirement.parse(
+ "%s ==%s" % (requirement.project_name, version))
+
+ return requirement
+
def install(self, specs, working_set=None):
logger.debug('Installing %r', specs)
@@ -366,9 +394,11 @@
if dest is not None and dest not in path:
path.insert(0, dest)
- requirements = [pkg_resources.Requirement.parse(spec)
+ requirements = [self._constrain(pkg_resources.Requirement.parse(spec))
for spec in specs]
+
+
if working_set is None:
ws = pkg_resources.WorkingSet([])
else:
@@ -392,6 +422,7 @@
ws.resolve(requirements)
except pkg_resources.DistributionNotFound, err:
[requirement] = err
+ requirement = self._constrain(requirement)
if dest:
logger.debug('Getting required %s', requirement)
dist = self._get_dist(requirement, ws, self._always_unzip)
@@ -405,7 +436,7 @@
def build(self, spec, build_ext):
logger.debug('Building %r', spec)
- requirement = pkg_resources.Requirement.parse(spec)
+ requirement = self._constrain(pkg_resources.Requirement.parse(spec))
dist = self._satisfied(requirement)
if dist is not None:
@@ -465,17 +496,18 @@
def install(specs, dest,
links=(), index=None,
executable=sys.executable, always_unzip=False,
- path=None, working_set=None, newest=True):
+ path=None, working_set=None, newest=True, versions=None):
installer = Installer(dest, links, index, executable, always_unzip, path,
- newest)
+ newest, versions)
return installer.install(specs, working_set)
def build(spec, dest, build_ext,
links=(), index=None,
executable=sys.executable,
- path=None, newest=True):
- installer = Installer(dest, links, index, executable, True, path, newest)
+ path=None, newest=True, versions=None):
+ installer = Installer(dest, links, index, executable, True, path, newest,
+ versions)
return installer.build(spec, build_ext)
Modified: zc.buildout/trunk/src/zc/buildout/easy_install.txt
===================================================================
--- zc.buildout/trunk/src/zc/buildout/easy_install.txt 2007-03-06 11:35:37 UTC (rev 73005)
+++ zc.buildout/trunk/src/zc/buildout/easy_install.txt 2007-03-06 16:02:59 UTC (rev 73006)
@@ -78,6 +78,11 @@
not None, then the install function will search for the newest
distributions that satisfy the requirements.
+versions
+ A dictionary mapping project names to version numbers to be used
+ when selecting distributions. This can be used to specify a set of
+ distribution versions independent of other requirements.
+
The install method returns a working set containing the distributions
needed to meet the given requirements.
@@ -185,6 +190,76 @@
d demo-0.3-py2.4.egg
d demoneeded-1.1-py2.4.egg
+Specifying version information indepenent of requirements
+---------------------------------------------------------
+
+Sometimes it's useful to specify version information indepenent of
+normal requirements specifications. For example, a buildout may need
+to lock down a set of versions, without having to put put version
+numbers in setup files or part definitions. If a dictionary is passed
+to the install function, mapping project names to version numbers,
+then the versions numbers will be used.
+
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], dest, links=[link_server], index=link_server+'index/',
+ ... versions = dict(demo='0.2', demoneeded='1.0'))
+ >>> [d.version for d in ws]
+ ['0.2', '1.0']
+
+In this example, we specified a version for demoneeded, even though we
+didn't define a requirement for it. The versions specified apply to
+depenencies as well as the specified requirements.
+
+If we specify a version that's incompatible with a requirement, then
+we'll get an error:
+
+ >>> from zope.testing.loggingsupport import InstalledHandler
+ >>> handler = InstalledHandler('zc.buildout.easy_install')
+ >>> import logging
+ >>> logging.getLogger('zc.buildout.easy_install').propagate = False
+
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo >0.2'], dest, links=[link_server],
+ ... index=link_server+'index/',
+ ... versions = dict(demo='0.2', demoneeded='1.0'))
+ Traceback (most recent call last):
+ ...
+ IncompatibleVersionError: Bad version 0.2
+
+ >>> print handler
+ zc.buildout.easy_install DEBUG
+ Installing ['demo >0.2']
+ zc.buildout.easy_install ERROR
+ The version, 0.2, is not consistent with the requirement, demo>0.2
+
+ >>> handler.clear()
+
+If no versions are specified, a debugging message will be output
+reporting that a version was picked automatically:
+
+ >>> ws = zc.buildout.easy_install.install(
+ ... ['demo'], dest, links=[link_server], index=link_server+'index/',
+ ... )
+
+ >>> print handler
+ zc.buildout.easy_install DEBUG
+ Installing ['demo']
+ zc.buildout.easy_install DEBUG
+ We have the best distribution that satisfies
+ demo
+ zc.buildout.easy_install DEBUG
+ Picked version for demo = 0.3
+ zc.buildout.easy_install DEBUG
+ Getting required demoneeded
+ zc.buildout.easy_install DEBUG
+ We have the best distribution that satisfies
+ demoneeded
+ zc.buildout.easy_install DEBUG
+ Picked version for demoneeded = 1.1
+
+ >>> handler.uninstall()
+ >>> logging.getLogger('zc.buildout.easy_install').propagate = True
+
Script generation
-----------------
@@ -506,7 +581,12 @@
not None, then the install function will search for the newest
distributions that satisfy the requirements.
+versions
+ A dictionary mapping project names to version numbers to be used
+ when selecting distributions. This can be used to specify a set of
+ distribution versions independent of other requirements.
+
Our link server included a source distribution that includes a simple
extension, extdemo.c::
@@ -553,7 +633,9 @@
Now if we look in our destination directory, we see we have an extdemo egg:
>>> ls(dest)
+ - demo-0.2-py2.4.egg
d demo-0.3-py2.4.egg
+ - demoneeded-1.0-py2.4.egg
d demoneeded-1.1-py2.4.egg
d extdemo-1.4-py2.4-unix-i686.egg
@@ -589,7 +671,9 @@
'/sample-install/extdemo-1.4-py2.4-linux-i686.egg'
>>> ls(dest)
+ - demo-0.2-py2.4.egg
d demo-0.3-py2.4.egg
+ - demoneeded-1.0-py2.4.egg
d demoneeded-1.1-py2.4.egg
d extdemo-1.4-py2.4-unix-i686.egg
@@ -602,12 +686,33 @@
... links=[link_server], index=link_server+'index/')
'/sample-install/extdemo-1.5-py2.4-unix-i686.egg'
+ >>> ls(dest)
+ - demo-0.2-py2.4.egg
d demo-0.3-py2.4.egg
+ - demoneeded-1.0-py2.4.egg
d demoneeded-1.1-py2.4.egg
d extdemo-1.4-py2.4-unix-i686.egg
d extdemo-1.5-py2.4-unix-i686.egg
+The versions option also influences the versions used. For example,
+if we specify a version for extdemo, then that will be used, even
+though it isn't the newest. Let's clean out the destimation directory
+first:
+ >>> import os
+ >>> for name in os.listdir(dest):
+ ... remove(dest, name)
+
+ >>> zc.buildout.easy_install.build(
+ ... 'extdemo', dest,
+ ... {'include-dirs': os.path.join(sample_buildout, 'include')},
+ ... links=[link_server], index=link_server+'index/',
+ ... versions=dict(extdemo='1.4'))
+ '/sample-install/extdemo-1.4-py2.4-unix-i686.egg'
+
+ >>> ls(dest)
+ d extdemo-1.4-py2.4-unix-i686.egg
+
Handling custom build options for extensions in develop eggs
------------------------------------------------------------
@@ -657,10 +762,7 @@
egg link:
>>> ls(dest)
- d demo-0.3-py2.4.egg
- d demoneeded-1.1-py2.4.egg
- d extdemo-1.4-py2.4-linux-i686.egg
- d extdemo-1.5-py2.4-linux-i686.egg
+ d extdemo-1.4-py2.4-unix-i686.egg
- extdemo.egg-link
And that the source directory contains the compiled extension:
Modified: zc.buildout/trunk/src/zc/buildout/testing.py
===================================================================
--- zc.buildout/trunk/src/zc/buildout/testing.py 2007-03-06 11:35:37 UTC (rev 73005)
+++ zc.buildout/trunk/src/zc/buildout/testing.py 2007-03-06 16:02:59 UTC (rev 73006)
@@ -55,6 +55,13 @@
def mkdir(*path):
os.mkdir(os.path.join(*path))
+def remove(*path):
+ path = os.path.join(*path)
+ if os.path.isdir(path):
+ shutil.rmtree(path)
+ else:
+ os.remove(path)
+
def rmdir(*path):
shutil.rmtree(os.path.join(*path))
@@ -202,6 +209,7 @@
cat = cat,
mkdir = mkdir,
rmdir = rmdir,
+ remove = remove,
tmpdir = tmpdir,
write = write,
system = system,
Modified: zc.buildout/trunk/src/zc/buildout/testing.txt
===================================================================
--- zc.buildout/trunk/src/zc/buildout/testing.txt 2007-03-06 11:35:37 UTC (rev 73005)
+++ zc.buildout/trunk/src/zc/buildout/testing.txt 2007-03-06 16:02:59 UTC (rev 73006)
@@ -37,6 +37,10 @@
Remove a directory. The directory path is provided as one or
more strings, to be joined with os.path.join.
+``remove(*path)``
+ Remove a directory or file. The path is provided as one or
+ more strings, to be joined with os.path.join.
+
``tmpdir(name)``
Create a temporary directory with the given name. The directory
will be automatically removed at the end of the test. The path of
Modified: zc.buildout/trunk/src/zc/buildout/tests.py
===================================================================
--- zc.buildout/trunk/src/zc/buildout/tests.py 2007-03-06 11:35:37 UTC (rev 73005)
+++ zc.buildout/trunk/src/zc/buildout/tests.py 2007-03-06 16:02:59 UTC (rev 73006)
@@ -1436,6 +1436,8 @@
'zc.buildout.egg'),
(re.compile('creating \S*setup.cfg'), 'creating setup.cfg'),
(re.compile('hello\%ssetup' % os.path.sep), 'hello/setup'),
+ (re.compile('Picked version for (\S+) = \S+'),
+ 'Picked version for \\1 = V.V'),
])
),
More information about the Checkins
mailing list