From c13d5c58cbab03fd3238e11572a108950f442759 Mon Sep 17 00:00:00 2001 From: Jim Fulton <jim@zope.com> Date: Mon, 5 Feb 2007 23:03:44 +0000 Subject: [PATCH] Added newest keyword parameter to the install and build functions to allow for getting less than the newest but still getting what's necessary. --- src/zc/buildout/easy_install.py | 678 ++++++++++++++++--------------- src/zc/buildout/easy_install.txt | 87 +++- src/zc/buildout/tests.py | 15 +- 3 files changed, 439 insertions(+), 341 deletions(-) diff --git a/src/zc/buildout/easy_install.py b/src/zc/buildout/easy_install.py index dc07d92..17eb371 100644 --- a/src/zc/buildout/easy_install.py +++ b/src/zc/buildout/easy_install.py @@ -1,4 +1,4 @@ -############################################################################## +############################################################################# # # Copyright (c) 2005 Zope Corporation and Contributors. # All Rights Reserved. @@ -85,80 +85,7 @@ def _get_index(executable, index_url, find_links): _indexes[key] = index return index -def _satisfied(req, env, dest, executable, index, links): - dists = [dist for dist in env[req.project_name] if dist in req] - if not dists: - logger.debug('We have no distributions for %s', req.project_name) - return None - - # Note that dists are sorted from best to worst, as promised by - # env.__getitem__ - - for dist in dists: - if (dist.precedence == pkg_resources.DEVELOP_DIST): - logger.debug('We have a develop egg for %s', req) - return dist - - # Find an upprt limit in the specs, if there is one: - specs = [(pkg_resources.parse_version(v), op) for (op, v) in req.specs] - specs.sort() - maxv = None - greater = False - lastv = None - for v, op in specs: - if op == '==' and not greater: - maxv = v - elif op in ('>', '>=', '!='): - maxv = None - greater == True - elif op == '<': - maxv = None - greater == False - elif op == '<=': - maxv = v - greater == False - - if v == lastv: - # Repeated versions values are undefined, so - # all bets are off - maxv = None - greater = True - else: - lastv = v - - best_we_have = dists[0] # Because dists are sorted from best to worst - - # Check if we have the upper limit - if maxv is not None and best_we_have.version == maxv: - logger.debug('We have the best distribution that satisfies\n%s', - req) - return best_we_have - - # We have some installed distros. There might, theoretically, be - # newer ones. Let's find out which ones are available and see if - # any are newer. We only do this if we're willing to install - # something, which is only true if dest is not None: - - if dest is not None: - best_available = _get_index(executable, index, links).obtain(req) - else: - best_available = None - - if best_available is None: - # That's a bit odd. There aren't any distros available. - # We should use the best one we have that meets the requirement. - logger.debug( - 'There are no distros available that meet %s. Using our best.', req) - return best_we_have - else: - # Let's find out if we already have the best available: - if best_we_have.parsed_version >= best_available.parsed_version: - # Yup. Use it. - logger.debug('We have the best distribution that satisfies\n%s', req) - return best_we_have - - return None - +clear_index_cache = _indexes.clear if sys.platform == 'win32': # work around spawn lamosity on windows @@ -172,293 +99,384 @@ _easy_install_cmd = _safe_arg( 'from setuptools.command.easy_install import main; main()' ) -def _call_easy_install(spec, env, ws, dest, links, index, - executable, always_unzip): - - path = _get_dist(pkg_resources.Requirement.parse('setuptools'), - env, ws, dest, links, index, executable, False).location - - args = ('-c', _easy_install_cmd, '-mUNxd', _safe_arg(dest)) - if always_unzip: - args += ('-Z', ) - level = logger.getEffectiveLevel() - if level > logging.DEBUG: - args += ('-q', ) - elif level < logging.DEBUG: - args += ('-v', ) - - args += (spec, ) +class Installer: + + def __init__(self, + dest=None, + links=(), + index=None, + executable=sys.executable, + always_unzip=False, + path=None, + newest=True, + ): + self._dest = dest + self._links = list(links) + self._index_url = index + self._executable = executable + self._always_unzip = always_unzip + path = (path and path[:] or []) + buildout_and_setuptools_path + if dest is not None and dest not in path: + path.insert(0, dest) + self._path = path + self._newest = newest + self._env = pkg_resources.Environment(path, + python=_get_version(executable)) + self._index = _get_index(executable, index, links) + + def _satisfied(self, req): + dists = [dist for dist in self._env[req.project_name] if dist in req] + if not dists: + logger.debug('We have no distributions for %s', req.project_name) + return None + + # Note that dists are sorted from best to worst, as promised by + # env.__getitem__ + + for dist in dists: + if (dist.precedence == pkg_resources.DEVELOP_DIST): + logger.debug('We have a develop egg for %s', req) + return dist + + if not self._newest: + # We don't need the newest, so we'll use the newest one we + # find, which is the first returned by + # Environment.__getitem__. + return dists[0] + + # Find an upprt limit in the specs, if there is one: + specs = [(pkg_resources.parse_version(v), op) for (op, v) in req.specs] + specs.sort() + maxv = None + greater = False + lastv = None + for v, op in specs: + if op == '==' and not greater: + maxv = v + elif op in ('>', '>=', '!='): + maxv = None + greater == True + elif op == '<': + maxv = None + greater == False + elif op == '<=': + maxv = v + greater == False + + if v == lastv: + # Repeated versions values are undefined, so + # all bets are off + maxv = None + greater = True + else: + lastv = v - if level <= logging.DEBUG: - logger.debug('Running easy_install:\n%s "%s"\npath=%s\n', - executable, '" "'.join(args), path) + best_we_have = dists[0] # Because dists are sorted from best to worst - args += (dict(os.environ, PYTHONPATH=path), ) - sys.stdout.flush() # We want any pending output first - exit_code = os.spawnle(os.P_WAIT, executable, executable, *args) - assert exit_code == 0 + # Check if we have the upper limit + if maxv is not None and best_we_have.version == maxv: + logger.debug('We have the best distribution that satisfies\n%s', + req) + return best_we_have + # We have some installed distros. There might, theoretically, be + # newer ones. Let's find out which ones are available and see if + # any are newer. We only do this if we're willing to install + # something, which is only true if dest is not None: -def _get_dist(requirement, env, ws, - dest, links, index_url, executable, always_unzip): - - # Maybe an existing dist is already the best dist that satisfies the - # requirement - dist = _satisfied(requirement, env, dest, executable, index_url, links) + + if self._dest is not None: + best_available = self._index.obtain(req) + else: + best_available = None + + if best_available is None: + # That's a bit odd. There aren't any distros available. + # We should use the best one we have that meets the requirement. + logger.debug( + 'There are no distros available that meet %s. Using our best.', + req) + return best_we_have + else: + # Let's find out if we already have the best available: + if best_we_have.parsed_version >= best_available.parsed_version: + # Yup. Use it. + logger.debug( + 'We have the best distribution that satisfies\n%s', + req) + return best_we_have - if dist is None: - if dest is not None: - logger.info("Getting new distribution for %s", requirement) + return None - # Retrieve the dist: - index = _get_index(executable, index_url, links) - dist = index.obtain(requirement) - if dist is None: - raise zc.buildout.UserError( - "Couldn't find a distribution for %s." - % requirement) + def _call_easy_install(self, spec, ws, dest): - fname = dist.location - if url_match(fname): - fname = urlparse.urlparse(fname)[2] - - if fname.endswith('.egg'): - # It's already an egg, just fetch it into the dest - tmp = tempfile.mkdtemp('get_dist') - try: - dist = index.fetch_distribution(requirement, tmp) - if dist is None: - raise zc.buildout.UserError( - "Couln't download a distribution for %s." - % requirement) - - newloc = os.path.join( - dest, os.path.basename(dist.location)) - - if os.path.isdir(dist.location): - # we got a directory. It must have been - # obtained locally. Jut copy it. - shutil.copytree(dist.location, newloc) - else: - - if always_unzip: - should_unzip = True - else: - metadata = pkg_resources.EggMetadata( - zipimport.zipimporter(dist.location) - ) - should_unzip = ( - metadata.has_metadata('not-zip-safe') - or not metadata.has_metadata('zip-safe') - ) - - if should_unzip: - setuptools.archive_util.unpack_archive( - dist.location, newloc) + path = self._get_dist(pkg_resources.Requirement.parse('setuptools'), + ws, False).location + + args = ('-c', _easy_install_cmd, '-mUNxd', _safe_arg(dest)) + if self._always_unzip: + args += ('-Z', ) + level = logger.getEffectiveLevel() + if level > logging.DEBUG: + args += ('-q', ) + elif level < logging.DEBUG: + args += ('-v', ) + + args += (spec, ) + + if level <= logging.DEBUG: + logger.debug('Running easy_install:\n%s "%s"\npath=%s\n', + executable, '" "'.join(args), path) + + args += (dict(os.environ, PYTHONPATH=path), ) + sys.stdout.flush() # We want any pending output first + exit_code = os.spawnle(os.P_WAIT, self._executable, self._executable, + *args) + assert exit_code == 0 + + + def _get_dist(self, requirement, ws, always_unzip): + + # Maybe an existing dist is already the best dist that satisfies the + # requirement + dist = self._satisfied(requirement) + + if dist is None: + if self._dest is not None: + logger.info("Getting new distribution for %s", requirement) + + # Retrieve the dist: + index = self._index + dist = index.obtain(requirement) + if dist is None: + raise zc.buildout.UserError( + "Couldn't find a distribution for %s." + % requirement) + + fname = dist.location + if url_match(fname): + fname = urlparse.urlparse(fname)[2] + + if fname.endswith('.egg'): + # It's already an egg, just fetch it into the dest + tmp = tempfile.mkdtemp('get_dist') + try: + dist = index.fetch_distribution(requirement, tmp) + if dist is None: + raise zc.buildout.UserError( + "Couln't download a distribution for %s." + % requirement) + + newloc = os.path.join( + self._dest, os.path.basename(dist.location)) + + if os.path.isdir(dist.location): + # we got a directory. It must have been + # obtained locally. Jut copy it. + shutil.copytree(dist.location, newloc) else: - shutil.copyfile(dist.location, newloc) - - finally: - shutil.rmtree(tmp) + if self._always_unzip: + should_unzip = True + else: + metadata = pkg_resources.EggMetadata( + zipimport.zipimporter(dist.location) + ) + should_unzip = ( + metadata.has_metadata('not-zip-safe') + or not metadata.has_metadata('zip-safe') + ) + + if should_unzip: + setuptools.archive_util.unpack_archive( + dist.location, newloc) + else: + shutil.copyfile(dist.location, newloc) + + finally: + shutil.rmtree(tmp) + + else: + # It's some other kind of dist. We'll download it to + # a temporary directory and let easy_install have it's + # way with it: + tmp = tempfile.mkdtemp('get_dist') + try: + dist = index.fetch_distribution(requirement, tmp) + + # May need a new one. Call easy_install + self._call_easy_install(dist.location, ws, self._dest) + finally: + shutil.rmtree(tmp) + + + # Because we have added a new egg, we need to rescan + # the destination directory. + + # We may overwrite distributions, so clear importer + # cache. + sys.path_importer_cache.clear() + + self._env.scan([self._dest]) + dist = self._env.best_match(requirement, ws) + logger.info("Got %s", dist) else: - # It's some other kind of dist. We'll download it to - # a temporary directory and let easy_install have it's - # way with it: - tmp = tempfile.mkdtemp('get_dist') - try: - dist = index.fetch_distribution(requirement, tmp) - - # May need a new one. Call easy_install - _call_easy_install( - dist.location, env, ws, dest, links, index_url, - executable, always_unzip) - finally: - shutil.rmtree(tmp) - - - # Because we have added a new egg, we need to rescan - # the destination directory. - - # We may overwrite distributions, so clear importer - # cache. - sys.path_importer_cache.clear() - - env.scan([dest]) - dist = env.best_match(requirement, ws) - logger.info("Got %s", dist) - else: - dist = env.best_match(requirement, ws) + dist = self._env.best_match(requirement, ws) - if dist is None: - raise ValueError("Couldn't find", requirement) - - # XXX Need test for this - if dist.has_metadata('dependency_links.txt'): - for link in dist.get_metadata_lines('dependency_links.txt'): - link = link.strip() - if link not in links: - links.append(link) - - return dist + if dist is None: + raise ValueError("Couldn't find", requirement) + + # XXX Need test for this + if dist.has_metadata('dependency_links.txt'): + for link in dist.get_metadata_lines('dependency_links.txt'): + link = link.strip() + if link not in self._links: + self._links.append(link) + self._index = _get_index(self._executable, + self._index_url, self._links) + + return dist + + def _maybe_add_setuptools(self, ws, dist): + if dist.has_metadata('namespace_packages.txt'): + for r in dist.requires(): + if r.project_name == 'setuptools': + break + else: + # We have a namespace package but no requirement for setuptools + if dist.precedence == pkg_resources.DEVELOP_DIST: + logger.warn( + "Develop distribution for %s\n" + "uses namespace packages but the distribution " + "does not require setuptools.", + dist) + requirement = pkg_resources.Requirement.parse('setuptools') + if ws.find(requirement) is None: + dist = self._get_dist(requirement, ws, False) + ws.add(dist) -def _maybe_add_setuptools(ws, dist, env, dest, links, index, executable): - if dist.has_metadata('namespace_packages.txt'): - for r in dist.requires(): - if r.project_name == 'setuptools': - break - else: - # We have a namespace package but no requirement for setuptools - if dist.precedence == pkg_resources.DEVELOP_DIST: - logger.warn( - "Develop distribution for %s\n" - "uses namespace packages but the distribution " - "does not require setuptools.", - dist) - requirement = pkg_resources.Requirement.parse('setuptools') - if ws.find(requirement) is None: - dist = _get_dist(requirement, env, ws, - dest, links, index, executable, - False) - ws.add(dist) - - -def install(specs, dest, - links=(), index=None, - executable=sys.executable, always_unzip=False, - path=None, working_set=None): - logger.debug('Installing %r', specs) + def install(self, specs, working_set=None): - path = path and path[:] or [] - if dest is not None and dest not in path: - path.insert(0, dest) + logger.debug('Installing %r', specs) - path += buildout_and_setuptools_path + path = self._path + dest = self._dest + if dest is not None and dest not in path: + path.insert(0, dest) - links = list(links) # make copy, because we may need to mutate - + requirements = [pkg_resources.Requirement.parse(spec) + for spec in specs] - # For each spec, see if it is already installed. We create a working - # set to keep track of what we've collected and to make sue than the - # distributions assembled are consistent. - env = pkg_resources.Environment(path, python=_get_version(executable)) - requirements = [pkg_resources.Requirement.parse(spec) for spec in specs] + if working_set is None: + ws = pkg_resources.WorkingSet([]) + else: + ws = working_set - if working_set is None: - ws = pkg_resources.WorkingSet([]) - else: - ws = working_set - - for requirement in requirements: - dist = _get_dist(requirement, env, ws, - dest, links, index, executable, always_unzip) - ws.add(dist) - _maybe_add_setuptools(ws, dist, - env, dest, links, index, executable) - - # OK, we have the requested distributions and they're in the working - # set, but they may have unmet requirements. We'll simply keep - # trying to resolve requirements, adding missing requirements as they - # are reported. - # - # Note that we don't pass in the environment, because we - # want to look for new eggs unless what we have is the best that matches - # the requirement. - while 1: - try: - ws.resolve(requirements) - except pkg_resources.DistributionNotFound, err: - [requirement] = err - if dest: - logger.debug('Getting required %s', requirement) - dist = _get_dist(requirement, env, ws, - dest, links, index, executable, always_unzip) + for requirement in requirements: + dist = self._get_dist(requirement, ws, self._always_unzip) ws.add(dist) - _maybe_add_setuptools(ws, dist, - env, dest, links, index, executable) - else: - break - - return ws + self._maybe_add_setuptools(ws, dist) + + # OK, we have the requested distributions and they're in the working + # set, but they may have unmet requirements. We'll simply keep + # trying to resolve requirements, adding missing requirements as they + # are reported. + # + # Note that we don't pass in the environment, because we + # want to look for new eggs unless what we have is the best that matches + # the requirement. + while 1: + try: + ws.resolve(requirements) + except pkg_resources.DistributionNotFound, err: + [requirement] = err + if dest: + logger.debug('Getting required %s', requirement) + dist = self._get_dist(requirement, ws, self._always_unzip) + ws.add(dist) + self._maybe_add_setuptools(ws, dist) + else: + break -def build(spec, dest, build_ext, - links=(), index=None, - executable=sys.executable, - path=None): + return ws - index_url = index + def build(self, spec, build_ext): + logger.debug('Building %r', spec) - logger.debug('Building %r', spec) + requirement = pkg_resources.Requirement.parse(spec) - path = path and path[:] or [] - if dest is not None: - path.insert(0, dest) + dist = self._satisfied(requirement) + if dist is not None: + return dist.location - path += buildout_and_setuptools_path + undo = [] + try: + tmp = tempfile.mkdtemp('build') + undo.append(lambda : shutil.rmtree(tmp)) + tmp2 = tempfile.mkdtemp('build') + undo.append(lambda : shutil.rmtree(tmp2)) - links = list(links) # make copy, because we may need to mutate - - # For each spec, see if it is already installed. We create a working - # set to keep track of what we've collected and to make sue than the - # distributions assembled are consistent. - env = pkg_resources.Environment(path, python=_get_version(executable)) - requirement = pkg_resources.Requirement.parse(spec) + dist = self._index.fetch_distribution( + requirement, tmp2, False, True) + if dist is None: + raise zc.buildout.UserError( + "Couldn't find a source distribution for %s." + % requirement) + setuptools.archive_util.unpack_archive(dist.location, tmp) - dist = _satisfied(requirement, env, dest, executable, index_url, links) - if dist is not None: - return [dist.location] + if os.path.exists(os.path.join(tmp, 'setup.py')): + base = tmp + else: + setups = glob.glob(os.path.join(tmp, '*', 'setup.py')) + if not setups: + raise distutils.errors.DistutilsError( + "Couldn't find a setup script in %s" + % os.path.basename(dist.location) + ) + if len(setups) > 1: + raise distutils.errors.DistutilsError( + "Multiple setup scripts in %s" + % os.path.basename(dist.location) + ) + base = os.path.dirname(setups[0]) + + + setup_cfg = os.path.join(base, 'setup.cfg') + if not os.path.exists(setup_cfg): + f = open(setup_cfg, 'w') + f.close() + setuptools.command.setopt.edit_config( + setup_cfg, dict(build_ext=build_ext)) - undo = [] - try: - tmp = tempfile.mkdtemp('build') - undo.append(lambda : shutil.rmtree(tmp)) - tmp2 = tempfile.mkdtemp('build') - undo.append(lambda : shutil.rmtree(tmp2)) + tmp3 = tempfile.mkdtemp('build', dir=self._dest) + undo.append(lambda : shutil.rmtree(tmp3)) - index = _get_index(executable, index_url, links) - dist = index.fetch_distribution(requirement, tmp2, False, True) - if dist is None: - raise zc.buildout.UserError( - "Couldn't find a source distribution for %s." - % requirement) - setuptools.archive_util.unpack_archive(dist.location, tmp) + self._call_easy_install(base, pkg_resources.WorkingSet(), tmp3) - if os.path.exists(os.path.join(tmp, 'setup.py')): - base = tmp - else: - setups = glob.glob(os.path.join(tmp, '*', 'setup.py')) - if not setups: - raise distutils.errors.DistutilsError( - "Couldn't find a setup script in %s" - % os.path.basename(dist.location) - ) - if len(setups) > 1: - raise distutils.errors.DistutilsError( - "Multiple setup scripts in %s" - % os.path.basename(dist.location) - ) - base = os.path.dirname(setups[0]) + return _copyeggs(tmp3, self._dest, '.egg', undo) + finally: + undo.reverse() + [f() for f in undo] - setup_cfg = os.path.join(base, 'setup.cfg') - if not os.path.exists(setup_cfg): - f = open(setup_cfg, 'w') - f.close() - setuptools.command.setopt.edit_config( - setup_cfg, dict(build_ext=build_ext)) - tmp3 = tempfile.mkdtemp('build', dir=dest) - undo.append(lambda : shutil.rmtree(tmp3)) +def install(specs, dest, + links=(), index=None, + executable=sys.executable, always_unzip=False, + path=None, working_set=None, newest=True): + installer = Installer(dest, links, index, executable, always_unzip, path, + newest) + return installer.install(specs, working_set) - _call_easy_install(base, env, pkg_resources.WorkingSet(), - tmp3, links, index_url, executable, True) - return _copyeggs(tmp3, dest, '.egg', undo) - - finally: - undo.reverse() - [f() for f in undo] +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) + return installer.build(spec, build_ext) + def _rm(*paths): @@ -477,8 +495,8 @@ def _copyeggs(src, dest, suffix, undo): _rm(new) os.rename(os.path.join(src, name), new) result.append(new) - - assert len(result) == 1 + + assert len(result) == 1, str(result) undo.pop() return result[0] diff --git a/src/zc/buildout/easy_install.txt b/src/zc/buildout/easy_install.txt index e9292d3..1c2e007 100644 --- a/src/zc/buildout/easy_install.txt +++ b/src/zc/buildout/easy_install.txt @@ -21,7 +21,10 @@ level that is similar to easy_install, with a few exceptions: - Distutils options for building extensions can be passed. -The easy_install module provides a method, install, for installing one +Distribution installation +------------------------- + +The easy_install module provides a function, install, for installing one or more packages and their dependencies. The install function takes 2 positional arguments: @@ -68,6 +71,13 @@ working_set you to call install multiple times, if necessary, to gather multiple sets of requirements. +newest + A boolian value indicating whether to search for new distributions + when already-installed distributions meet the requirement. When + this is true, the default, and when the destination directory is + not None, then the install function will search for the newest + distributions that satisfy the requirements. + The install method returns a working set containing the distributions needed to meet the given requirements. @@ -111,8 +121,17 @@ And the actual eggs were added to the eggs directory. - demo-0.2-py2.4.egg - demoneeded-1.1-py2.4.egg -If we ask for the demo distribution without a version restriction, -we'll get the newer version: +If we remove the version restriction on demo, but specify a false +value for newest, no new didstributions will be installed: + + >>> ws = zc.buildout.easy_install.install( + ... ['demo'], dest, links=[link_server], index=link_server+'index/', + ... newest=False) + >>> ls(dest) + - demo-0.2-py2.4.egg + - demoneeded-1.1-py2.4.egg + +If we leave off the newst option, we'll get an update for demo: >>> ws = zc.buildout.easy_install.install( ... ['demo'], dest, links=[link_server], index=link_server+'index/') @@ -480,9 +499,13 @@ path A list of additional directories to search for locally-installed distributions. -always_unzip - A flag indicating that newly-downloaded distributions should be - directories even if they could be installed as zip files. +newest + A boolian value indicating whether to search for new distributions + when already-installed distributions meet the requirement. When + this is true, the default, and when the destination directory is + not None, then the install function will search for the newest + distributions that satisfy the requirements. + Our link server included a source distribution that includes a simple extension, extdemo.c:: @@ -534,6 +557,57 @@ Now if we look in our destination directory, we see we have an extdemo egg: d demoneeded-1.1-py2.4.egg d extdemo-1.4-py2.4-unix-i686.egg +Let's update our link server with a new version of extdemo: + + >>> update_extdemo() + >>> print get(link_server), + <html><body> + <a href="demo-0.1-py2.4.egg">demo-0.1-py2.4.egg</a><br> + <a href="demo-0.2-py2.4.egg">demo-0.2-py2.4.egg</a><br> + <a href="demo-0.3-py2.4.egg">demo-0.3-py2.4.egg</a><br> + <a href="demoneeded-1.0.zip">demoneeded-1.0.zip</a><br> + <a href="demoneeded-1.1.zip">demoneeded-1.1.zip</a><br> + <a href="extdemo-1.4.zip">extdemo-1.4.zip</a><br> + <a href="extdemo-1.5.zip">extdemo-1.5.zip</a><br> + <a href="index/">index/</a><br> + <a href="other-1.0-py2.4.egg">other-1.0-py2.4.egg</a><br> + </body></html> + +The easy_install caches information about servers to reduce network +access. To see the update, we have to call the clear_index_cache +function to clear the index cache: + + >>> zc.buildout.easy_install.clear_index_cache() + +If we run build with newest set to False, we won't get an update: + + >>> zc.buildout.easy_install.build( + ... 'extdemo', dest, + ... {'include-dirs': os.path.join(sample_buildout, 'include')}, + ... links=[link_server], index=link_server+'index/', + ... newest=False) + '/sample-install/extdemo-1.4-py2.4-linux-i686.egg' + + >>> ls(dest) + d demo-0.3-py2.4.egg + d demoneeded-1.1-py2.4.egg + d extdemo-1.4-py2.4-unix-i686.egg + +But if we run it with the default True setting for newest, then we'll +get an updated egg: + + >>> zc.buildout.easy_install.build( + ... 'extdemo', dest, + ... {'include-dirs': os.path.join(sample_buildout, 'include')}, + ... links=[link_server], index=link_server+'index/') + '/sample-install/extdemo-1.5-py2.4-unix-i686.egg' + + d demo-0.3-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 + + Handling custom build options for extensions in develop eggs ------------------------------------------------------------ @@ -586,6 +660,7 @@ egg link: 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 - extdemo.egg-link And that the source directory contains the compiled extension: diff --git a/src/zc/buildout/tests.py b/src/zc/buildout/tests.py index 31696c4..8e51b5a 100644 --- a/src/zc/buildout/tests.py +++ b/src/zc/buildout/tests.py @@ -1047,19 +1047,22 @@ initextdemo(void) extdemo_setup_py = """ from distutils.core import setup, Extension -setup(name = "extdemo", version = "1.4", url="http://www.zope.org", +setup(name = "extdemo", version = "%s", url="http://www.zope.org", author="Demo", author_email="demo@demo.com", ext_modules = [Extension('extdemo', ['extdemo.c'])], ) """ -def add_source_dist(test): - - tmp = test.globs['extdemo'] = test.globs['tmpdir']('extdemo') +def add_source_dist(test, version=1.4): + + if 'extdemo' not in test.globs: + test.globs['extdemo'] = test.globs['tmpdir']('extdemo') + + tmp = test.globs['extdemo'] write = test.globs['write'] try: write(tmp, 'extdemo.c', extdemo_c); - write(tmp, 'setup.py', extdemo_setup_py); + write(tmp, 'setup.py', extdemo_setup_py % version); write(tmp, 'README', ""); write(tmp, 'MANIFEST.in', "include *.c\n"); test.globs['sdist'](tmp, test.globs['sample_eggs']) @@ -1075,7 +1078,9 @@ def easy_install_SetUp(test): add_source_dist(test) test.globs['link_server'] = test.globs['start_server']( test.globs['sample_eggs']) + test.globs['update_extdemo'] = lambda : add_source_dist(test, 1.5) + egg_parse = re.compile('([0-9a-zA-Z_.]+)-([0-9a-zA-Z_.]+)-py(\d[.]\d).egg$' ).match def makeNewRelease(project, ws, dest): -- 2.30.9