Commit 768502ce authored by Godefroid Chapelle's avatar Godefroid Chapelle

Problem: `setuptools.easy_install` is deprecated

Solution: Use `pip install`

The meat of the change is in src/zc/buildout/easy_install.py

Some tests had to be refactored a bit to make them more robust.

`tox` is removed to avoid issues due to sharing the same directory
between different virtual environments; `Makefile` enriched to make
per python virtual envs depend on source files.

No need to be afraid of default Python install as we depend on `pip`.
`bootstrap.py` is gone as not needed anymore.
parent 0185dc6a
name: Buildout on Centos name: Test in Centos container
on: [push] on: [push, pull_request]
jobs: jobs:
build: build:
......
scripts.cfg
\ No newline at end of file
...@@ -9,7 +9,7 @@ jobs: ...@@ -9,7 +9,7 @@ jobs:
strategy: strategy:
max-parallel: 4 max-parallel: 4
matrix: matrix:
python-version: [2.7, 3.5, 3.6, 3.7] python-version: [3.5, 3.6, 3.7, 3.8]
package: [zest.releaser, pyspf] package: [zest.releaser, pyspf]
steps: steps:
......
...@@ -11,7 +11,7 @@ jobs: ...@@ -11,7 +11,7 @@ jobs:
strategy: strategy:
max-parallel: 4 max-parallel: 4
matrix: matrix:
python-version: [2.7, 3.5, 3.6, 3.7] python-version: [3.5, 3.6, 3.7, 3.8]
package: [zest.releaser, pyspf] package: [zest.releaser, pyspf]
steps: steps:
......
...@@ -6,6 +6,7 @@ develop-eggs/ ...@@ -6,6 +6,7 @@ develop-eggs/
eggs/ eggs/
parts/ parts/
python*/ python*/
venvs/
*.pyc *.pyc
*.egg *.egg
*.egg-info *.egg-info
......
Change History Change History
************** **************
2.13.4 (unreleased) 3.0.0 (unreleased)
=================== ==================
- Use ``pip install`` instead of deprecated ``setuptools.easy_install``.
- Patch ``pkg_resources.Distribution`` to make install of unpinned versions quicker. - Patch ``pkg_resources.Distribution`` to make install of unpinned versions quicker.
Most obvious with ``setuptools``. Most obvious with ``setuptools``.
......
...@@ -44,8 +44,8 @@ PYTHON_DOWNLOAD = $(PYTHON_BUILD_DIR)/$(PYTHON_ARCHIVE).tgz ...@@ -44,8 +44,8 @@ PYTHON_DOWNLOAD = $(PYTHON_BUILD_DIR)/$(PYTHON_ARCHIVE).tgz
BUILD_DIRS = $(PYTHON_PATH) bin build develop-eggs eggs parts BUILD_DIRS = $(PYTHON_PATH) bin build develop-eggs eggs parts
all: test all: all_test
.PHONY: all download_python python build test docker clean .PHONY: all download_python python build test docker clean all_pythons all_test
# setup python from source # setup python from source
$(PYTHON_DOWNLOAD): $(PYTHON_DOWNLOAD):
...@@ -74,12 +74,46 @@ python: $(PYTHON_PATH)/bin/$(PYTHON_EXE) ...@@ -74,12 +74,46 @@ python: $(PYTHON_PATH)/bin/$(PYTHON_EXE)
build: python build: python
$(PYTHON_PATH)/bin/$(PYTHON_EXE) dev.py $(PYTHON_PATH)/bin/$(PYTHON_EXE) dev.py
# copy to virtualenvs
ROOT_FILES := $(HERE)/setup.py $(HERE)/setup.cfg $(HERE)/dev.py $(HERE)/README.rst $(HERE)/CHANGES.rst $(HERE)/buildout.cfg
SRC_FILES := $(shell find $(HERE)/src ! -path '*egg-info*' \( -name '*.py' -o -name '*.txt' -o -name '*.test' \) )
RCP_FILES := $(shell find $(HERE)/zc.recipe.egg_ ! -path '*egg-info*' \( -name '*.py' -o -name '*.txt' -o -name '*.rst' -o -name '*.cfg' -o -name '*.in' \) )
DOC_FILES := $(shell find $(HERE)/doc -name '*.rst' -o -name '*.txt')
ALL_COPY := $(subst $(HERE),$(VENV),$(SRC_FILES) $(DOC_FILES) $(RCP_FILES) $(ROOT_FILES))
# Generate rules to map sources into targets
$(foreach s,$(ALL_COPY),$(eval $s: $(VENV)/bin/$(PYTHON_EXE) $(subst $(VENV),$(HERE),$s)))
$(ALL_COPY):
@mkdir -p $(dir $@)
@cp $(subst $(VENV),$(HERE),$@) $@
$(VENV)/bin/$(PYTHON_EXE): $(PYTHON_PATH)/bin/$(PYTHON_EXE)
@command -v virtualenv >/dev/null 2>&1 || { echo "virtualenv required but not installed" >&2; exit 1; }
test -d "$(HERE)/venvs" || mkdir -p $(HERE)/venvs
virtualenv -p $(PYTHON_PATH)/bin/$(PYTHON_EXE) $(VENV)
$(VENV)/bin/test: $(VENV)/bin/$(PYTHON_EXE) $(ALL_COPY)
cd $(VENV) && bin/$(PYTHON_EXE) dev.py --no-clean
test: $(VENV)/bin/test
$(VENV)/bin/test -c -vvv $(testargs)
all_pythons:
$(MAKE) PYTHON_VER=3.5 python
$(MAKE) PYTHON_VER=3.6 python
$(MAKE) PYTHON_VER=3.7 python
$(MAKE) PYTHON_VER=3.8 python
all_test:
$(MAKE) PYTHON_VER=3.5 test
$(MAKE) PYTHON_VER=3.6 test
$(MAKE) PYTHON_VER=3.7 test
$(MAKE) PYTHON_VER=3.8 test
docker: docker:
docker build -f .github/workflows/Dockerfile --tag centos_buildout:python${PYTHON_VER} --build-arg PYTHON_VER=${PYTHON_VER} . docker build -f .github/workflows/Dockerfile --tag centos_buildout:python${PYTHON_VER} --build-arg PYTHON_VER=${PYTHON_VER} .
docker run centos_buildout:python${PYTHON_VER} /buildout/bin/test -c -vvv -t abi docker run centos_buildout:python${PYTHON_VER} /buildout/bin/test -c -vvv -t abi
clean: clean:
rm -rf $(BUILD_DIRS) $(PYTHON_BUILD_DIR) rm -rf $(VENVS) $(PYTHON_BUILD_DIR) $(HERE)/pythons
test:
$(HERE)/bin/test -1 -vvv -c
ifeq ($(PYTHON_VER),2.7) PYTHON_CONFIGURE_ARGS ?=
PYTHON_CONFIGURE_ARGS ?=
endif
ifeq ($(PYTHON_VER),3.5)
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip
endif
ifeq ($(PYTHON_VER),3.6)
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip
endif
ifeq ($(PYTHON_VER),3.7)
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip
endif
ifeq ($(PYTHON_VER),3.8)
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip
endif
...@@ -6,19 +6,19 @@ ifeq ($(PYTHON_VER),2.7) ...@@ -6,19 +6,19 @@ ifeq ($(PYTHON_VER),2.7)
endif endif
ifeq ($(PYTHON_VER),3.5) ifeq ($(PYTHON_VER),3.5)
BUILD_VARIABLES = LDFLAGS="-L$(OPENSSL)/lib" CPPFLAGS="-I$(OPENSSL)/include" BUILD_VARIABLES = LDFLAGS="-L$(OPENSSL)/lib" CPPFLAGS="-I$(OPENSSL)/include"
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip PYTHON_CONFIGURE_ARGS ?=
endif endif
ifeq ($(PYTHON_VER),3.6) ifeq ($(PYTHON_VER),3.6)
BUILD_VARIABLES = LDFLAGS="-L$(OPENSSL)/lib" CPPFLAGS="-I$(OPENSSL)/include" BUILD_VARIABLES = LDFLAGS="-L$(OPENSSL)/lib" CPPFLAGS="-I$(OPENSSL)/include"
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip PYTHON_CONFIGURE_ARGS ?=
endif endif
ifeq ($(PYTHON_VER),3.7) ifeq ($(PYTHON_VER),3.7)
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip --with-openssl=$(OPENSSL) PYTHON_CONFIGURE_ARGS ?= --with-openssl=$(OPENSSL)
endif endif
ifeq ($(PYTHON_VER),3.8) ifeq ($(PYTHON_VER),3.8)
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip --with-openssl=$(OPENSSL) PYTHON_CONFIGURE_ARGS ?= --with-openssl=$(OPENSSL)
endif endif
ifeq ($(PYTHON_VER),3.9) ifeq ($(PYTHON_VER),3.9)
PYTHON_CONFIGURE_ARGS ?= --without-ensurepip --with-openssl=$(OPENSSL) PYTHON_CONFIGURE_ARGS ?= --with-openssl=$(OPENSSL)
endif endif
##############################################################################
#
# Copyright (c) 2006 Zope Foundation 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.
#
##############################################################################
"""Bootstrap a buildout-based project
Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
"""
import os
import shutil
import sys
import tempfile
from optparse import OptionParser
__version__ = '2015-07-01'
# See zc.buildout's changelog if this version is up to date.
tmpeggs = tempfile.mkdtemp(prefix='bootstrap-')
usage = '''\
[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
Bootstraps a buildout-based project.
Simply run this script in a directory containing a buildout.cfg, using the
Python that you want bin/buildout to use.
Note that by using --find-links to point to local resources, you can keep
this script from going over the network.
'''
parser = OptionParser(usage=usage)
parser.add_option("--version",
action="store_true", default=False,
help=("Return bootstrap.py version."))
parser.add_option("-t", "--accept-buildout-test-releases",
dest='accept_buildout_test_releases',
action="store_true", default=False,
help=("Normally, if you do not specify a --buildout-version, "
"the bootstrap script and buildout gets the newest "
"*final* versions of zc.buildout and its recipes and "
"extensions for you. If you use this flag, "
"bootstrap and buildout will get the newest releases "
"even if they are alphas or betas."))
parser.add_option("-c", "--config-file",
help=("Specify the path to the buildout configuration "
"file to be used."))
parser.add_option("-f", "--find-links",
help=("Specify a URL to search for buildout releases"))
parser.add_option("--allow-site-packages",
action="store_true", default=False,
help=("Let bootstrap.py use existing site packages"))
parser.add_option("--buildout-version",
help="Use a specific zc.buildout version")
parser.add_option("--setuptools-version",
help="Use a specific setuptools version")
parser.add_option("--setuptools-to-dir",
help=("Allow for re-use of existing directory of "
"setuptools versions"))
options, args = parser.parse_args()
if options.version:
print("bootstrap.py version %s" % __version__)
sys.exit(0)
######################################################################
# load/install setuptools
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
ez = {}
if os.path.exists('ez_setup.py'):
exec(open('ez_setup.py').read(), ez)
else:
exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
if not options.allow_site_packages:
# ez_setup imports site, which adds site packages
# this will remove them from the path to ensure that incompatible versions
# of setuptools are not in the path
import site
# inside a virtualenv, there is no 'getsitepackages'.
# We can't remove these reliably
if hasattr(site, 'getsitepackages'):
for sitepackage_path in site.getsitepackages():
# Strip all site-packages directories from sys.path that
# are not sys.prefix; this is because on Windows
# sys.prefix is a site-package directory.
if sitepackage_path != sys.prefix:
sys.path[:] = [x for x in sys.path
if sitepackage_path not in x]
setup_args = dict(to_dir=tmpeggs, download_delay=0)
if options.setuptools_version is not None:
setup_args['version'] = options.setuptools_version
if options.setuptools_to_dir is not None:
setup_args['to_dir'] = options.setuptools_to_dir
ez['use_setuptools'](**setup_args)
import setuptools
import pkg_resources
# This does not (always?) update the default working set. We will
# do it.
for path in sys.path:
if path not in pkg_resources.working_set.entries:
pkg_resources.working_set.add_entry(path)
######################################################################
# Install buildout
ws = pkg_resources.working_set
setuptools_path = ws.find(
pkg_resources.Requirement.parse('setuptools')).location
# Fix sys.path here as easy_install.pth added before PYTHONPATH
cmd = [sys.executable, '-c',
'import sys; sys.path[0:0] = [%r]; ' % setuptools_path +
'from setuptools.command.easy_install import main; main()',
'-mZqNxd', tmpeggs]
find_links = os.environ.get(
'bootstrap-testing-find-links',
options.find_links or
('http://downloads.buildout.org/'
if options.accept_buildout_test_releases else None)
)
if find_links:
cmd.extend(['-f', find_links])
requirement = 'zc.buildout'
version = options.buildout_version
if version is None and not options.accept_buildout_test_releases:
# Figure out the most recent final version of zc.buildout.
import setuptools.package_index
_final_parts = '*final-', '*final'
def _final_version(parsed_version):
try:
return not parsed_version.is_prerelease
except AttributeError:
# Older setuptools
for part in parsed_version:
if (part[:1] == '*') and (part not in _final_parts):
return False
return True
index = setuptools.package_index.PackageIndex(
search_path=[setuptools_path])
if find_links:
index.add_find_links((find_links,))
req = pkg_resources.Requirement.parse(requirement)
if index.obtain(req) is not None:
best = []
bestv = None
for dist in index[req.project_name]:
distv = dist.parsed_version
if _final_version(distv):
if bestv is None or distv > bestv:
best = [dist]
bestv = distv
elif distv == bestv:
best.append(dist)
if best:
best.sort()
version = best[-1].version
if version:
requirement = '=='.join((requirement, version))
cmd.append(requirement)
import subprocess
if subprocess.call(cmd) != 0:
raise Exception(
"Failed to execute command:\n%s" % repr(cmd)[1:-1])
######################################################################
# Import and run buildout
ws.add_entry(tmpeggs)
ws.require(requirement)
import zc.buildout.buildout
if not [a for a in args if '=' not in a]:
args.append('bootstrap')
# if -c was provided, we push it back into args for buildout' main function
if options.config_file is not None:
args[0:0] = ['-c', options.config_file]
zc.buildout.buildout.main(args)
shutil.rmtree(tmpeggs)
...@@ -23,56 +23,70 @@ for d in 'eggs', 'develop-eggs', 'bin', 'parts': ...@@ -23,56 +23,70 @@ for d in 'eggs', 'develop-eggs', 'bin', 'parts':
if not os.path.exists(d): if not os.path.exists(d):
os.mkdir(d) os.mkdir(d)
bin_buildout = os.path.join('bin', 'buildout')
if os.path.isfile(bin_buildout):
os.remove(bin_buildout)
if os.path.isdir('build'): if os.path.isdir('build'):
shutil.rmtree('build') shutil.rmtree('build')
###################################################################### ######################################################################
# Make sure we have a relatively clean environment def check_upgrade(package):
try: print('')
import pkg_resources, setuptools print('Check %s' % package)
except ImportError: print('')
pass
else:
raise SystemError(
"Buildout development with a pre-installed setuptools or "
"distribute is not supported.")
######################################################################
# Install distribute
ez = {}
try: try:
from urllib.request import urlopen sys.stdout.flush()
except ImportError: output = subprocess.check_output(
from urllib2 import urlopen [sys.executable] + ['-m', 'pip', 'install', '--upgrade', package],
)
# XXX use a more permanent ez_setup.py URL when available. was_up_to_date = b"up-to-date" in output
exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez) if not was_up_to_date:
ez['use_setuptools'](to_dir='eggs', download_delay=0) print(output.decode('utf8'))
return not was_up_to_date
import pkg_resources, setuptools except subprocess.CalledProcessError:
setuptools_path = os.path.dirname(os.path.dirname(setuptools.__file__)) raise RuntimeError("Upgrade %s failed." % package)
need_restart = False
for package in ['pip', 'setuptools', 'wheel']:
did_upgrade = check_upgrade(package)
need_restart = need_restart or did_upgrade
if need_restart:
print("Restart")
sys.stdout.flush()
return_code = subprocess.call(
[sys.executable] + sys.argv
)
sys.exit(return_code)
###################################################################### ######################################################################
# Install buildout print('')
print('Install buildout')
print('')
sys.stdout.flush()
if subprocess.call( if subprocess.call(
[sys.executable] + [sys.executable] +
['setup.py', '-q', 'develop', '-m', '-x', '-d', 'develop-eggs'], ['setup.py', '-q', 'develop', '-m', '-x', '-d', 'develop-eggs'],
env=dict(os.environ, PYTHONPATH=setuptools_path)): ):
raise RuntimeError("buildout build failed.") raise RuntimeError("buildout build failed.")
import pkg_resources
pkg_resources.working_set.add_entry('src') pkg_resources.working_set.add_entry('src')
import zc.buildout.easy_install import zc.buildout.easy_install
zc.buildout.easy_install.scripts( zc.buildout.easy_install.scripts(
['zc.buildout'], pkg_resources.working_set , sys.executable, 'bin') ['zc.buildout'], pkg_resources.working_set , sys.executable, 'bin')
######################################################################
print('')
print('Run buildout')
print('')
bin_buildout = os.path.join('bin', 'buildout') bin_buildout = os.path.join('bin', 'buildout')
if sys.platform.startswith('java'): if sys.platform.startswith('java'):
# Jython needs the script to be called twice via sys.executable # Jython needs the script to be called twice via sys.executable
assert subprocess.Popen([sys.executable] + [bin_buildout]).wait() == 0 assert subprocess.Popen([sys.executable, bin_buildout, '-N']).wait() == 0
if sys.version_info < (2, 6): sys.stdout.flush()
bin_buildout = [bin_buildout, '-c2.4.cfg']
sys.exit(subprocess.Popen(bin_buildout).wait()) sys.exit(subprocess.Popen(bin_buildout).wait())
...@@ -431,7 +431,7 @@ where you list them, as in: ...@@ -431,7 +431,7 @@ where you list them, as in:
>>> shutil.rmtree('eggs') >>> shutil.rmtree('eggs')
>>> run_buildout('buildout show-picked-versions=true') >>> run_buildout('buildout show-picked-versions=true')
>>> yup([n for n in ls('eggs') if n.startswith('bobo-2.3.0-')]) >>> yup([n for n in ls('eggs') if n.startswith('bobo-2.3.0-')])
>>> yup('bobo = 2.3.0' in read('out')) >>> yup('bobo==2.3.0' in read('out'))
In this example, we've requested a version of bobo less than 5.0. In this example, we've requested a version of bobo less than 5.0.
......
...@@ -11,7 +11,6 @@ ignore = ...@@ -11,7 +11,6 @@ ignore =
Makefile.configure.Darwin Makefile.configure.Darwin
zc.recipe.egg_/* zc.recipe.egg_/*
zc.recipe.egg_ zc.recipe.egg_
tox.ini
.github/* .github/*
.github .github
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
# #
############################################################################## ##############################################################################
name = "zc.buildout" name = "zc.buildout"
version = '2.13.4.dev0' version = '3.0.0.dev0'
import os import os
from setuptools import setup from setuptools import setup
...@@ -47,6 +47,8 @@ setup( ...@@ -47,6 +47,8 @@ setup(
namespace_packages = ['zc'], namespace_packages = ['zc'],
install_requires = [ install_requires = [
'setuptools>=8.0', 'setuptools>=8.0',
'pip',
'wheel',
], ],
include_package_data = True, include_package_data = True,
entry_points = entry_points, entry_points = entry_points,
......
...@@ -13,9 +13,15 @@ ...@@ -13,9 +13,15 @@
############################################################################## ##############################################################################
"""Buildout package """Buildout package
""" """
import sys
import zc.buildout.patches # NOQA import zc.buildout.patches # NOQA
WINDOWS = sys.platform.startswith('win')
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
class UserError(Exception): class UserError(Exception):
"""Errors made by a user """Errors made by a user
""" """
......
...@@ -1094,7 +1094,7 @@ class Buildout(DictMixin): ...@@ -1094,7 +1094,7 @@ class Buildout(DictMixin):
return return
ws = zc.buildout.easy_install.install( ws = zc.buildout.easy_install.install(
('zc.buildout', 'setuptools'), ('zc.buildout', 'setuptools', 'pip', 'wheel'),
self['buildout']['eggs-directory'], self['buildout']['eggs-directory'],
links = self['buildout'].get('find-links', '').split(), links = self['buildout'].get('find-links', '').split(),
index = self['buildout'].get('index'), index = self['buildout'].get('index'),
...@@ -1107,7 +1107,7 @@ class Buildout(DictMixin): ...@@ -1107,7 +1107,7 @@ class Buildout(DictMixin):
# recorded in easy_install.py. We use that here to check if we've been # recorded in easy_install.py. We use that here to check if we've been
# upgraded. # upgraded.
start_locations = zc.buildout.easy_install.buildout_and_setuptools_path start_locations = zc.buildout.easy_install.buildout_and_setuptools_path
for project in 'zc.buildout', 'setuptools': for project in 'zc.buildout', 'setuptools', 'pip', 'wheel':
req = pkg_resources.Requirement.parse(project) req = pkg_resources.Requirement.parse(project)
if ws.find(req).location not in start_locations: if ws.find(req).location not in start_locations:
upgraded.append(ws.find(req)) upgraded.append(ws.find(req))
...@@ -1131,7 +1131,7 @@ class Buildout(DictMixin): ...@@ -1131,7 +1131,7 @@ class Buildout(DictMixin):
"buildout command.") "buildout command.")
return return
self._logger.info("Upgraded:\n %s;\nrestarting.", self._logger.info("Upgraded:\n %s;\nRestarting.",
",\n ".join([("%s version %s" ",\n ".join([("%s version %s"
% (dist.project_name, dist.version) % (dist.project_name, dist.version)
) )
......
...@@ -55,7 +55,9 @@ The ``bin`` directory contains scripts:: ...@@ -55,7 +55,9 @@ The ``bin`` directory contains scripts::
The ``eggs`` directory has installed distributions: The ``eggs`` directory has installed distributions:
>>> ls(sample_buildout, 'eggs') >>> ls(sample_buildout, 'eggs')
- setuptools-0.7-py3.3.egg - pip.egg-link
- setuptools.egg-link
- wheel.egg-link
- zc.buildout.egg-link - zc.buildout.egg-link
The ``develop-eggs`` and ``parts`` directories are initially empty:: The ``develop-eggs`` and ``parts`` directories are initially empty::
...@@ -2838,11 +2840,8 @@ database is shown:: ...@@ -2838,11 +2840,8 @@ database is shown::
... """) ... """)
>>> print_(system(buildout+' -vv'), end='') # doctest: +NORMALIZE_WHITESPACE >>> print_(system(buildout+' -vv'), end='') # doctest: +NORMALIZE_WHITESPACE
Installing 'zc.buildout', 'setuptools'. Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
We have a develop egg: zc.buildout 1.0.0. ...
We have the best distribution that satisfies 'setuptools'.
Picked: setuptools = 0.7
<BLANKLINE>
Configuration data: Configuration data:
[buildout] [buildout]
allow-hosts = * allow-hosts = *
...@@ -3108,8 +3107,10 @@ We also get other buildout artifacts:: ...@@ -3108,8 +3107,10 @@ We also get other buildout artifacts::
>>> _ = (ls(sample_bootstrapped, 'eggs'), >>> _ = (ls(sample_bootstrapped, 'eggs'),
... ls(sample_bootstrapped, 'develop-eggs')) ... ls(sample_bootstrapped, 'develop-eggs'))
- setuptools-0.7-py2.3.egg - pip.egg-link
- zc.buildout-1.0-py2.3.egg - setuptools.egg-link
- wheel.egg-link
- zc.buildout.egg-link
(We list both the ``eggs`` and ``develop-eggs`` directories because the (We list both the ``eggs`` and ``develop-eggs`` directories because the
buildout or setuptools egg could be installed in the ``develop-eggs`` buildout or setuptools egg could be installed in the ``develop-eggs``
......
...@@ -36,7 +36,10 @@ import sys ...@@ -36,7 +36,10 @@ import sys
import tempfile import tempfile
import zc.buildout import zc.buildout
import zc.buildout.rmtree import zc.buildout.rmtree
from zc.buildout import WINDOWS
from zc.buildout import PY3
import warnings import warnings
import csv
try: try:
from setuptools.wheel import Wheel # This is the important import from setuptools.wheel import Wheel # This is the important import
...@@ -48,6 +51,9 @@ try: ...@@ -48,6 +51,9 @@ try:
except ImportError: except ImportError:
SETUPTOOLS_SUPPORTS_WHEELS = False SETUPTOOLS_SUPPORTS_WHEELS = False
BIN_SCRIPTS = 'Scripts' if WINDOWS else 'bin'
warnings.filterwarnings( warnings.filterwarnings(
'ignore', '.+is being parsed as a legacy, non PEP 440, version') 'ignore', '.+is being parsed as a legacy, non PEP 440, version')
...@@ -90,6 +96,7 @@ if has_distribute and not has_setuptools: ...@@ -90,6 +96,7 @@ if has_distribute and not has_setuptools:
# function to narrow to just the buildout and setuptools paths. # function to narrow to just the buildout and setuptools paths.
buildout_and_setuptools_path = [d.location for d in pkg_resources.working_set] buildout_and_setuptools_path = [d.location for d in pkg_resources.working_set]
setuptools_path = buildout_and_setuptools_path setuptools_path = buildout_and_setuptools_path
pip_path = buildout_and_setuptools_path
FILE_SCHEME = re.compile('file://', re.I).match FILE_SCHEME = re.compile('file://', re.I).match
DUNDER_FILE_PATTERN = re.compile(r"__file__ = '(?P<filename>.+)'$") DUNDER_FILE_PATTERN = re.compile(r"__file__ = '(?P<filename>.+)'$")
...@@ -175,7 +182,7 @@ def _execute_permission(): ...@@ -175,7 +182,7 @@ def _execute_permission():
return 0o777 - current_umask return 0o777 - current_umask
_easy_install_cmd = 'from setuptools.command.easy_install import main; main()' _pip_install_cmd = 'from pip.__main__ import _main; _main()'
def get_namespace_package_paths(dist): def get_namespace_package_paths(dist):
""" """
...@@ -382,7 +389,7 @@ class Installer(object): ...@@ -382,7 +389,7 @@ class Installer(object):
logger.debug( logger.debug(
'There are no distros available that meet %r.\n' 'There are no distros available that meet %r.\n'
'Using our best, %s.', 'Using our best, %s.',
str(req), best_available) str(req), best_we_have)
return best_we_have, None return best_we_have, None
if self._prefer_final: if self._prefer_final:
...@@ -416,11 +423,11 @@ class Installer(object): ...@@ -416,11 +423,11 @@ class Installer(object):
str(req)) str(req))
return best_we_have, None return best_we_have, None
def _call_easy_install(self, spec, dest, dist): def _call_pip_install(self, spec, dest, dist):
tmp = tempfile.mkdtemp(dir=dest) tmp = tempfile.mkdtemp(dir=dest)
try: try:
paths = call_easy_install(spec, tmp) paths = call_pip_install(spec, tmp)
dists = [] dists = []
env = pkg_resources.Environment(paths) env = pkg_resources.Environment(paths)
...@@ -831,7 +838,7 @@ class Installer(object): ...@@ -831,7 +838,7 @@ class Installer(object):
setuptools.command.setopt.edit_config( setuptools.command.setopt.edit_config(
setup_cfg, dict(build_ext=build_ext)) setup_cfg, dict(build_ext=build_ext))
dists = self._call_easy_install(base, self._dest, dist) dists = self._call_pip_install(base, self._dest, dist)
return [dist.location for dist in dists] return [dist.location for dist in dists]
finally: finally:
...@@ -960,9 +967,14 @@ buildout_and_setuptools_dists = list(install(['zc.buildout'], None, ...@@ -960,9 +967,14 @@ buildout_and_setuptools_dists = list(install(['zc.buildout'], None,
check_picked=False)) check_picked=False))
buildout_and_setuptools_path = [d.location buildout_and_setuptools_path = [d.location
for d in buildout_and_setuptools_dists] for d in buildout_and_setuptools_dists]
setuptools_path = [d.location
for d in install(['setuptools'], None, check_picked=False)] pip_dists = [d for d in buildout_and_setuptools_dists if d.project_name != 'zc.buildout']
setuptools_pythonpath = os.pathsep.join(setuptools_path) pip_path = [d.location for d in pip_dists]
pip_pythonpath = os.pathsep.join(pip_path)
setuptools_path = pip_path
setuptools_pythonpath = pip_pythonpath
def build(spec, dest, build_ext, def build(spec, dest, build_ext,
links=(), index=None, links=(), index=None,
...@@ -1625,17 +1637,17 @@ class IncompatibleConstraintError(zc.buildout.UserError): ...@@ -1625,17 +1637,17 @@ class IncompatibleConstraintError(zc.buildout.UserError):
IncompatibleVersionError = IncompatibleConstraintError # Backward compatibility IncompatibleVersionError = IncompatibleConstraintError # Backward compatibility
def call_easy_install(spec, dest): def call_pip_install(spec, dest):
""" """
Call `easy_install` from setuptools as a subprocess to install a Call `pip install` from a subprocess to install a
distribution specified by `spec` into `dest`. distribution specified by `spec` into `dest`.
Returns all the paths inside `dest` created by the above. Returns all the paths inside `dest` created by the above.
""" """
path = setuptools_path path = pip_path
args = [sys.executable, '-c', args = [sys.executable, '-c',
('import sys; sys.path[0:0] = %r; ' % path) + ('import sys; sys.path[0:0] = %r; ' % path) +
_easy_install_cmd, '-mZUNxd', dest] _pip_install_cmd, 'install', '--no-deps', '-t', dest]
level = logger.getEffectiveLevel() level = logger.getEffectiveLevel()
if level > 0: if level > 0:
args.append('-q') args.append('-q')
...@@ -1645,7 +1657,7 @@ def call_easy_install(spec, dest): ...@@ -1645,7 +1657,7 @@ def call_easy_install(spec, dest):
args.append(spec) args.append(spec)
if level <= logging.DEBUG: if level <= logging.DEBUG:
logger.debug('Running easy_install:\n"%s"\npath=%s\n', logger.debug('Running pip install:\n"%s"\npath=%s\n',
'" "'.join(args), path) '" "'.join(args), path)
sys.stdout.flush() # We want any pending output first sys.stdout.flush() # We want any pending output first
...@@ -1658,7 +1670,109 @@ def call_easy_install(spec, dest): ...@@ -1658,7 +1670,109 @@ def call_easy_install(spec, dest):
"Look above this message for any errors that " "Look above this message for any errors that "
"were output by easy_install.", "were output by easy_install.",
spec) spec)
return glob.glob(os.path.join(dest, '*'))
split_entries = [os.path.splitext(entry) for entry in os.listdir(dest)]
try:
distinfo_dir = [
base + ext for base, ext in split_entries if ext == ".dist-info"
][0]
except IndexError:
logger.error(
"No .dist-info directory after installing %s",
spec)
raise
return make_egg_after_pip_install(dest, distinfo_dir)
def make_egg_after_pip_install(dest, distinfo_dir):
"""build properly named egg directory"""
# `pip install` does not build the namespace aware __init__.py files
# but they are needed in egg directories.
# Add them before moving files setup by pip
ns_file = os.path.join(dest, distinfo_dir, 'namespace_packages.txt')
if os.path.exists(ns_file):
with open(ns_file) as f:
namespace_packages = [
line.strip().replace('.', os.path.sep)
for line in f.readlines()
]
for namespace_package in namespace_packages:
init_py_file = os.path.join(dest, namespace_package, '__init__.py')
with open(init_py_file, 'w') as f:
f.write(
"__import__('pkg_resources').declare_namespace(__name__)"
)
# Remove `bin` directory if needed
# as there is no way to avoid script installation
# when running `pip install`
ep_file = os.path.join(dest, distinfo_dir, 'entry_points.txt')
if os.path.exists(ep_file):
with open(ep_file) as f:
content = f.read()
if "console_scripts" in content or "gui_scripts" in content:
bin_dir = os.path.join(dest, BIN_SCRIPTS)
if os.path.exists(bin_dir):
shutil.rmtree(bin_dir)
# Make properly named new egg dir
distro = [d for d in pkg_resources.find_distributions(dest)][0]
egg_name = distro.egg_name() + '.egg'
egg_dir = os.path.join(dest, egg_name)
os.mkdir(egg_dir)
# Move ".dist-info" dir into new egg dir
os.rename(
os.path.join(dest, distinfo_dir),
os.path.join(egg_dir, distinfo_dir)
)
with open(os.path.join(egg_dir, distinfo_dir, 'top_level.txt')) as f:
top_levels = filter(
(lambda x: len(x) != 0),
[line.strip() for line in f.readlines()]
)
# Move all top_level modules or packages
for top_level in top_levels:
# as package
top_level_dir = os.path.join(dest, top_level)
if os.path.exists(top_level_dir):
shutil.move(top_level_dir, egg_dir)
continue
# as module
top_level_py = top_level_dir + '.py'
if os.path.exists(top_level_py):
shutil.move(top_level_py, egg_dir)
top_level_pyc = top_level_dir + '.pyc'
if os.path.exists(top_level_pyc):
shutil.move(top_level_pyc, egg_dir)
continue
if PY3:
with open(os.path.join(egg_dir, distinfo_dir, 'RECORD'), newline='') as f:
all_files = [row[0] for row in csv.reader(f)]
else:
with open(os.path.join(egg_dir, distinfo_dir, 'RECORD'), 'rb') as f:
all_files = [row[0] for row in csv.reader(f)]
# There might be some c extensions left over
for entry in all_files:
if entry.endswith(('.pyc', '.pyo')):
continue
dest_entry = os.path.join(dest, entry)
# work around pip install -t bug that leaves entries in RECORD
# that starts with '../../'
if not os.path.abspath(dest_entry).startswith(dest):
continue
egg_entry = os.path.join(egg_dir, entry)
if os.path.exists(dest_entry) and not os.path.exists(egg_entry):
os.rename(dest_entry, egg_entry)
return [egg_dir]
def unpack_egg(location, dest): def unpack_egg(location, dest):
...@@ -1730,6 +1844,7 @@ def _move_to_eggs_dir_and_compile(dist, dest): ...@@ -1730,6 +1844,7 @@ def _move_to_eggs_dir_and_compile(dist, dest):
raise raise
tmp_dest = tempfile.mkdtemp(dir=dest) tmp_dest = tempfile.mkdtemp(dir=dest)
try: try:
installed_with_pip = False
if (os.path.isdir(dist.location) and if (os.path.isdir(dist.location) and
dist.precedence >= pkg_resources.BINARY_DIST): dist.precedence >= pkg_resources.BINARY_DIST):
# We got a pre-built directory. It must have been obtained locally. # We got a pre-built directory. It must have been obtained locally.
...@@ -1740,9 +1855,13 @@ def _move_to_eggs_dir_and_compile(dist, dest): ...@@ -1740,9 +1855,13 @@ def _move_to_eggs_dir_and_compile(dist, dest):
# It is an archive of some sort. # It is an archive of some sort.
# Figure out how to unpack it, or fall back to easy_install. # Figure out how to unpack it, or fall back to easy_install.
_, ext = os.path.splitext(dist.location) _, ext = os.path.splitext(dist.location)
unpacker = UNPACKERS.get(ext, call_easy_install) if ext in UNPACKERS:
unpacker(dist.location, tmp_dest) unpacker = UNPACKERS[ext]
[tmp_loc] = glob.glob(os.path.join(tmp_dest, '*')) unpacker(dist.location, tmp_dest)
[tmp_loc] = glob.glob(os.path.join(tmp_dest, '*'))
else:
[tmp_loc] = call_pip_install(dist.location, tmp_dest)
installed_with_pip = True
# We have installed the dist. Now try to rename/move it. # We have installed the dist. Now try to rename/move it.
newloc = os.path.join(dest, os.path.basename(tmp_loc)) newloc = os.path.join(dest, os.path.basename(tmp_loc))
...@@ -1777,4 +1896,6 @@ def _move_to_eggs_dir_and_compile(dist, dest): ...@@ -1777,4 +1896,6 @@ def _move_to_eggs_dir_and_compile(dist, dest):
finally: finally:
# Remember that temporary directories must be removed # Remember that temporary directories must be removed
zc.buildout.rmtree.rmtree(tmp_dest) zc.buildout.rmtree.rmtree(tmp_dest)
if installed_with_pip:
newdist.precedence = pkg_resources.EGG_DIST
return newdist return newdist
...@@ -345,7 +345,7 @@ reporting that a version was picked automatically: ...@@ -345,7 +345,7 @@ reporting that a version was picked automatically:
zc.buildout.easy_install DEBUG zc.buildout.easy_install DEBUG
Fetching demoneeded 1.1 from: http://.../demoneeded-1.1.zip Fetching demoneeded 1.1 from: http://.../demoneeded-1.1.zip
zc.buildout.easy_install DEBUG zc.buildout.easy_install DEBUG
Running easy_install:... Running pip install:...
zc.buildout.easy_install INFO zc.buildout.easy_install INFO
Got demoneeded 1.1. Got demoneeded 1.1.
zc.buildout.easy_install DEBUG zc.buildout.easy_install DEBUG
......
...@@ -127,10 +127,8 @@ about versions used. If we run the buildout in verbose mode without ...@@ -127,10 +127,8 @@ about versions used. If we run the buildout in verbose mode without
specifying a versions section: specifying a versions section:
>>> print_(system(buildout+' buildout:versions= -v'), end='') >>> print_(system(buildout+' buildout:versions= -v'), end='')
Installing 'zc.buildout', 'setuptools'. Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
We have a develop egg: zc.buildout 1.0.0. ...
We have the best distribution that satisfies 'setuptools'.
Picked: setuptools = 0.6
Installing 'spam'. Installing 'spam'.
We have the best distribution that satisfies 'spam'. We have the best distribution that satisfies 'spam'.
Picked: spam = 2. Picked: spam = 2.
...@@ -149,10 +147,8 @@ that we can fix them in a versions section. ...@@ -149,10 +147,8 @@ that we can fix them in a versions section.
If we run the buildout with the versions section: If we run the buildout with the versions section:
>>> print_(system(buildout+' -v'), end='') >>> print_(system(buildout+' -v'), end='')
Installing 'zc.buildout', 'setuptools'. Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
We have a develop egg: zc.buildout 1.0.0. ...
We have the best distribution that satisfies 'setuptools'.
Picked: setuptools = 0.6
Installing 'spam'. Installing 'spam'.
We have the distribution that satisfies 'spam==1'. We have the distribution that satisfies 'spam==1'.
Uninstalling foo. Uninstalling foo.
...@@ -180,10 +176,8 @@ versions for. ...@@ -180,10 +176,8 @@ versions for.
... ''' % join('recipe', 'dist')) ... ''' % join('recipe', 'dist'))
>>> print_(system(buildout+' -v'), end='') >>> print_(system(buildout+' -v'), end='')
Installing 'zc.buildout', 'setuptools'. Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
We have a develop egg: zc.buildout 1.0.0. ...
We have the best distribution that satisfies 'setuptools'.
Picked: setuptools = 0.6
Installing 'spam >0'. Installing 'spam >0'.
We have the distribution that satisfies 'spam==1'. We have the distribution that satisfies 'spam==1'.
Uninstalling foo. Uninstalling foo.
...@@ -202,7 +196,6 @@ versions: ...@@ -202,7 +196,6 @@ versions:
... allow-picked-versions = false ... allow-picked-versions = false
... ...
... [versions] ... [versions]
... spam = 1
... eggs = 2.2 ... eggs = 2.2
... ...
... [foo] ... [foo]
...@@ -211,9 +204,11 @@ versions: ...@@ -211,9 +204,11 @@ versions:
>>> print_(system(buildout), end='') # doctest: +ELLIPSIS >>> print_(system(buildout), end='') # doctest: +ELLIPSIS
While: While:
Installing. Installing.
Checking for upgrades. Getting section foo.
Getting distribution for 'setuptools'. Initializing section foo.
Error: Picked: setuptools = 0.6.30 Installing recipe spam.
Getting distribution for 'spam'.
Error: Picked: spam = 2
We can name a version something else, if we wish, using the versions option: We can name a version something else, if we wish, using the versions option:
...@@ -265,12 +260,14 @@ Since buildout 2.0, the functionality of the `buildout-versions ...@@ -265,12 +260,14 @@ Since buildout 2.0, the functionality of the `buildout-versions
<http://packages.python.org/buildout-versions/>`_ extension is part of <http://packages.python.org/buildout-versions/>`_ extension is part of
buildout itself. This makes reporting and managing versions easier. buildout itself. This makes reporting and managing versions easier.
Buildout picks a version for setuptools and for the tests, we need to grab the Buildout picks versions for pip and setuptools and for the tests, we need to grab the
version number: version number:
>>> import pkg_resources >>> import pkg_resources
>>> req = pkg_resources.Requirement.parse('setuptools') >>> req = pkg_resources.Requirement.parse('setuptools')
>>> setuptools_version = pkg_resources.working_set.find(req).version >>> setuptools_version = pkg_resources.working_set.find(req).version
>>> req = pkg_resources.Requirement.parse('pip')
>>> pip_version = pkg_resources.working_set.find(req).version
If you set the ``show-picked-versions`` option, buildout will print If you set the ``show-picked-versions`` option, buildout will print
versions it picked at the end of its run: versions it picked at the end of its run:
...@@ -293,7 +290,6 @@ versions it picked at the end of its run: ...@@ -293,7 +290,6 @@ versions it picked at the end of its run:
Versions had to be automatically picked. Versions had to be automatically picked.
The following part definition lists the versions picked: The following part definition lists the versions picked:
[versions] [versions]
setuptools = 0.6.99
spam = 2 spam = 2
When everything is pinned, no output is generated: When everything is pinned, no output is generated:
...@@ -306,12 +302,13 @@ When everything is pinned, no output is generated: ...@@ -306,12 +302,13 @@ When everything is pinned, no output is generated:
... show-picked-versions = true ... show-picked-versions = true
... ...
... [versions] ... [versions]
... pip = %s
... setuptools = %s ... setuptools = %s
... spam = 2 ... spam = 2
... ...
... [foo] ... [foo]
... recipe = spam ... recipe = spam
... ''' % (join('recipe', 'dist'), setuptools_version)) ... ''' % (join('recipe', 'dist'), pip_version, setuptools_version))
>>> print_(system(buildout), end='') # doctest: +ELLIPSIS >>> print_(system(buildout), end='') # doctest: +ELLIPSIS
Updating foo. Updating foo.
recipe v2 recipe v2
...@@ -330,12 +327,13 @@ and case differences won't impact the pinning: ...@@ -330,12 +327,13 @@ and case differences won't impact the pinning:
... show-picked-versions = true ... show-picked-versions = true
... ...
... [versions] ... [versions]
... pip = %s
... setuptools = %s ... setuptools = %s
... Spam = 2 ... Spam = 2
... ...
... [foo] ... [foo]
... recipe = spam ... recipe = spam
... ''' % (join('recipe', 'dist'), setuptools_version)) ... ''' % (join('recipe', 'dist'), pip_version, setuptools_version))
>>> print_(system(buildout), end='') # doctest: +ELLIPSIS >>> print_(system(buildout), end='') # doctest: +ELLIPSIS
Updating foo. Updating foo.
recipe v2 recipe v2
...@@ -347,9 +345,10 @@ extending from that versions file: ...@@ -347,9 +345,10 @@ extending from that versions file:
>>> write('my_versions.cfg', >>> write('my_versions.cfg',
... ''' ... '''
... [versions] ... [versions]
... pip = %s
... setuptools = %s ... setuptools = %s
... spam = 2 ... spam = 2
... ''' % setuptools_version) ... ''' % (pip_version, setuptools_version))
>>> write('buildout.cfg', >>> write('buildout.cfg',
... ''' ... '''
... [buildout] ... [buildout]
...@@ -372,8 +371,9 @@ at the end. ...@@ -372,8 +371,9 @@ at the end.
>>> write('my_versions.cfg', >>> write('my_versions.cfg',
... ''' ... '''
... [versions] ... [versions]
... pip = %s
... setuptools = %s ... setuptools = %s
... ''' % setuptools_version) ... ''' % (pip_version, setuptools_version))
>>> write('buildout.cfg', >>> write('buildout.cfg',
... ''' ... '''
... [buildout] ... [buildout]
...@@ -416,8 +416,9 @@ printing them to the console): ...@@ -416,8 +416,9 @@ printing them to the console):
>>> write('my_versions.cfg', >>> write('my_versions.cfg',
... ''' ... '''
... [versions] ... [versions]
... pip = %s
... setuptools = %s ... setuptools = %s
... ''' % setuptools_version) ... ''' % (pip_version, setuptools_version))
>>> write('buildout.cfg', >>> write('buildout.cfg',
... ''' ... '''
... [buildout] ... [buildout]
......
...@@ -25,7 +25,7 @@ except ImportError: ...@@ -25,7 +25,7 @@ except ImportError:
import errno import errno
import logging import logging
from multiprocessing import Process from multiprocessing import get_context
import os import os
import pkg_resources import pkg_resources
import random import random
...@@ -168,7 +168,7 @@ def _runsetup(setup, *args): ...@@ -168,7 +168,7 @@ def _runsetup(setup, *args):
zc.buildout.easy_install.call_subprocess( zc.buildout.easy_install.call_subprocess(
[sys.executable, setup] + args, [sys.executable, setup] + args,
env=dict(os.environ, env=dict(os.environ,
PYTHONPATH=zc.buildout.easy_install.setuptools_pythonpath, PYTHONPATH=zc.buildout.easy_install.pip_pythonpath,
), ),
) )
if os.path.exists('build'): if os.path.exists('build'):
...@@ -601,12 +601,6 @@ ignore_not_upgrading = ( ...@@ -601,12 +601,6 @@ ignore_not_upgrading = (
'Not upgrading because not running a local buildout command.\n' 'Not upgrading because not running a local buildout command.\n'
), '') ), '')
easy_install_deprecated = (
re.compile(
'WARNING: The easy_install command is deprecated and will be removed in a future version.\n'
), '')
def run_buildout(command): def run_buildout(command):
# Make sure we don't get .buildout # Make sure we don't get .buildout
os.environ['HOME'] = os.path.join(os.getcwd(), 'home') os.environ['HOME'] = os.path.join(os.getcwd(), 'home')
...@@ -621,7 +615,8 @@ def run_from_process(target, *args, **kw): ...@@ -621,7 +615,8 @@ def run_from_process(target, *args, **kw):
target(*args, **kw) target(*args, **kw)
def run_in_process(*args, **kwargs): def run_in_process(*args, **kwargs):
process = Process(target=run_from_process, args=args, kwargs=kwargs) ctx = get_context('fork')
process = ctx.Process(target=run_from_process, args=args, kwargs=kwargs)
process.daemon = True process.daemon = True
process.start() process.start()
process.join(99) process.join(99)
......
...@@ -12,8 +12,7 @@ zc.buildout.testing. ...@@ -12,8 +12,7 @@ zc.buildout.testing.
The handlers before calling set up are: The handlers before calling set up are:
>>> import logging >>> import logging
>>> len(logging.getLogger().handlers) >>> count = len(logging.getLogger().handlers)
1
>>> logging.getLogger().handlers # doctest: +ELLIPSIS >>> logging.getLogger().handlers # doctest: +ELLIPSIS
[<...NullHandler...>] [<...NullHandler...>]
...@@ -24,15 +23,15 @@ After calling it, a ``logging.StreamHandler`` was added: ...@@ -24,15 +23,15 @@ After calling it, a ``logging.StreamHandler`` was added:
>>> test = doctest.DocTestParser().get_doctest( >>> test = doctest.DocTestParser().get_doctest(
... '>>> x', {}, 'foo', 'foo.py', 0) ... '>>> x', {}, 'foo', 'foo.py', 0)
>>> zc.buildout.testing.buildoutSetUp(test) >>> zc.buildout.testing.buildoutSetUp(test)
>>> len(logging.getLogger().handlers) >>> len(logging.getLogger().handlers) == count + 1
2 True
>>> logging.getLogger().handlers # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE >>> logging.getLogger().handlers # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
[<...NullHandler...StreamHandler...>] [<...NullHandler...StreamHandler...>]
But tear down removes the new logging handler: But tear down removes the new logging handler:
>>> zc.buildout.testing.buildoutTearDown(test) >>> zc.buildout.testing.buildoutTearDown(test)
>>> len(logging.getLogger().handlers) >>> len(logging.getLogger().handlers) == count
1 True
>>> logging.getLogger().handlers # doctest: +ELLIPSIS >>> logging.getLogger().handlers # doctest: +ELLIPSIS
[<...NullHandler...>] [<...NullHandler...>]
This diff is collapsed.
...@@ -7,8 +7,6 @@ demonstrate this, we've created some "new releases" of buildout and ...@@ -7,8 +7,6 @@ demonstrate this, we've created some "new releases" of buildout and
setuptools in a new_releases folder: setuptools in a new_releases folder:
>>> ls(new_releases) >>> ls(new_releases)
d setuptools
- setuptools-99.99-py2.4.egg
d zc.buildout d zc.buildout
- zc.buildout-99.99-py2.4.egg - zc.buildout-99.99-py2.4.egg
...@@ -43,7 +41,7 @@ zc.buildout used: ...@@ -43,7 +41,7 @@ zc.buildout used:
... pass ... pass
... ...
... def install(self): ... def install(self):
... for project in 'zc.buildout', 'setuptools': ... for project in ['zc.buildout']:
... req = pkg_resources.Requirement.parse(project) ... req = pkg_resources.Requirement.parse(project)
... print_(project, pkg_resources.working_set.find(req).version) ... print_(project, pkg_resources.working_set.find(req).version)
... return () ... return ()
...@@ -68,17 +66,13 @@ new versions found in new releases: ...@@ -68,17 +66,13 @@ new versions found in new releases:
>>> print_(system(buildout), end='') >>> print_(system(buildout), end='')
Getting distribution for 'zc.buildout>=1.99'. Getting distribution for 'zc.buildout>=1.99'.
Got zc.buildout 99.99. Got zc.buildout 99.99.
Getting distribution for 'setuptools'.
Got setuptools 99.99.
Upgraded: Upgraded:
zc.buildout version 99.99, zc.buildout version 99.99;
setuptools version 99.99; Restarting.
restarting.
Generated script '/sample-buildout/bin/buildout'. Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/showversions' Develop: '/sample-buildout/showversions'
Installing show-versions. Installing show-versions.
zc.buildout 99.99 zc.buildout 99.99
setuptools 99.99
Our buildout script has been updated to use the new eggs: Our buildout script has been updated to use the new eggs:
...@@ -87,8 +81,8 @@ Our buildout script has been updated to use the new eggs: ...@@ -87,8 +81,8 @@ Our buildout script has been updated to use the new eggs:
<BLANKLINE> <BLANKLINE>
import sys import sys
sys.path[0:0] = [ sys.path[0:0] = [
'/sample-buildout/eggs/setuptools-99.99-py2.4.egg',
'/sample-buildout/eggs/zc.buildout-99.99-py2.4.egg', '/sample-buildout/eggs/zc.buildout-99.99-py2.4.egg',
...
] ]
<BLANKLINE> <BLANKLINE>
import zc.buildout.buildout import zc.buildout.buildout
...@@ -110,7 +104,6 @@ will install earlier versions of these packages: ...@@ -110,7 +104,6 @@ will install earlier versions of these packages:
... ...
... [versions] ... [versions]
... zc.buildout = < 99 ... zc.buildout = < 99
... setuptools = < 99
... ...
... [show-versions] ... [show-versions]
... recipe = showversions ... recipe = showversions
...@@ -120,14 +113,12 @@ Now we can see that we actually "upgrade" to an earlier version. ...@@ -120,14 +113,12 @@ Now we can see that we actually "upgrade" to an earlier version.
>>> print_(system(buildout), end='') >>> print_(system(buildout), end='')
Upgraded: Upgraded:
zc.buildout version 1.4.4; zc.buildout version 1.4.4,
setuptools version 0.6; Restarting.
restarting.
Generated script '/sample-buildout/bin/buildout'. Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/showversions' Develop: '/sample-buildout/showversions'
Updating show-versions. Updating show-versions.
zc.buildout 1.0.0 zc.buildout 1.4.4
setuptools 0.6
There are a number of cases, described below, in which the updates There are a number of cases, described below, in which the updates
don't happen. don't happen.
...@@ -150,7 +141,6 @@ We won't upgrade in offline mode: ...@@ -150,7 +141,6 @@ We won't upgrade in offline mode:
Develop: '/sample-buildout/showversions' Develop: '/sample-buildout/showversions'
Updating show-versions. Updating show-versions.
zc.buildout 1.0.0 zc.buildout 1.0.0
setuptools 0.6
Or in non-newest mode: Or in non-newest mode:
...@@ -158,7 +148,6 @@ Or in non-newest mode: ...@@ -158,7 +148,6 @@ Or in non-newest mode:
Develop: '/sample-buildout/showversions' Develop: '/sample-buildout/showversions'
Updating show-versions. Updating show-versions.
zc.buildout 1.0.0 zc.buildout 1.0.0
setuptools 0.6
We also won't upgrade if the buildout script being run isn't in the We also won't upgrade if the buildout script being run isn't in the
buildouts bin directory. To see this we'll create a new buildout buildouts bin directory. To see this we'll create a new buildout
...@@ -181,8 +170,6 @@ directory: ...@@ -181,8 +170,6 @@ directory:
Creating directory '/sample_buildout2/develop-eggs'. Creating directory '/sample_buildout2/develop-eggs'.
Getting distribution for 'zc.buildout>=1.99'. Getting distribution for 'zc.buildout>=1.99'.
Got zc.buildout 99.99. Got zc.buildout 99.99.
Getting distribution for 'setuptools'.
Got setuptools 99.99.
Not upgrading because not running a local buildout command. Not upgrading because not running a local buildout command.
>>> ls('bin') >>> ls('bin')
...@@ -205,15 +192,13 @@ directory: ...@@ -205,15 +192,13 @@ directory:
>>> print_(system(buildout), end='') >>> print_(system(buildout), end='')
Upgraded: Upgraded:
zc.buildout version 99.99, zc.buildout version 99.99;
setuptools version 99.99; Restarting.
restarting.
Generated script '/sample-buildout/bin/buildout'. Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/showversions' Develop: '/sample-buildout/showversions'
Unused options for buildout: 'relative-paths'. Unused options for buildout: 'relative-paths'.
Updating show-versions. Updating show-versions.
zc.buildout 99.99 zc.buildout 99.99
setuptools 99.99
>>> cat('bin', 'buildout') # doctest +ELL >>> cat('bin', 'buildout') # doctest +ELL
#!/usr/local/bin/python2.7 #!/usr/local/bin/python2.7
...@@ -227,7 +212,7 @@ directory: ...@@ -227,7 +212,7 @@ directory:
import sys import sys
sys.path[0:0] = [ sys.path[0:0] = [
join(base, 'eggs/zc.buildout-99.99-py3.3.egg'), join(base, 'eggs/zc.buildout-99.99-py3.3.egg'),
join(base, 'eggs/setuptools-99.99-py3.3.egg'), ...
] ]
<BLANKLINE> <BLANKLINE>
import zc.buildout.buildout import zc.buildout.buildout
...@@ -282,7 +267,6 @@ gives us a sys.exit: ...@@ -282,7 +267,6 @@ gives us a sys.exit:
... ...
... [versions] ... [versions]
... zc.buildout = < 99 ... zc.buildout = < 99
... setuptools = < 99
... ...
... [fail] ... [fail]
... recipe = failrecipe ... recipe = failrecipe
...@@ -292,9 +276,8 @@ Run the buildout: ...@@ -292,9 +276,8 @@ Run the buildout:
>>> print_(system(buildout, with_exit_code=True), end='') >>> print_(system(buildout, with_exit_code=True), end='')
Upgraded: Upgraded:
zc.buildout version 1.4.4; zc.buildout version 1.4.4,
setuptools version 0.6; Restarting.
restarting.
Generated script '/sample-buildout/bin/buildout'. Generated script '/sample-buildout/bin/buildout'.
Develop: '/sample-buildout/failrecipe' Develop: '/sample-buildout/failrecipe'
recipe sys-exits recipe sys-exits
......
[tox]
envlist =
py27,py34,py35,py36
[testenv]
commands =
pip install coverage
# buildout's dev.py wants python to not have setuptools
pip uninstall -y zc.buildout setuptools pip
python dev.py
{toxinidir}/bin/test -1 -vvv -c
coverage combine
coverage report
# since we're removing setuptools we can't possibly reuse the virtualenv
recreate = true
# if the user has ccache installed, PATH may contain /usr/lib/ccache that has a
# gcc wrapper that fails to build anything when buildout's tests set HOME to a
# non-existent directory under /tmp
setenv =
PATH=/usr/bin:/bin
...@@ -75,7 +75,9 @@ Now, if we look at the buildout eggs directory: ...@@ -75,7 +75,9 @@ Now, if we look at the buildout eggs directory:
>>> ls(sample_buildout, 'eggs') >>> ls(sample_buildout, 'eggs')
d demo-0.2-py2.3.egg d demo-0.2-py2.3.egg
d demoneeded-1.1-py2.3.egg d demoneeded-1.1-py2.3.egg
- setuptools-0.7-py2.3.egg - pip.egg-link
- setuptools.egg-link
- wheel.egg-link
d zc.buildout-1.0-py2.3.egg d zc.buildout-1.0-py2.3.egg
We see that we got an egg for demo that met the requirement, as well We see that we got an egg for demo that met the requirement, as well
...@@ -264,7 +266,9 @@ We didn't get an update for demo: ...@@ -264,7 +266,9 @@ We didn't get an update for demo:
>>> ls(sample_buildout, 'eggs') >>> ls(sample_buildout, 'eggs')
d demo-0.2-py2.3.egg d demo-0.2-py2.3.egg
d demoneeded-1.1-py2.3.egg d demoneeded-1.1-py2.3.egg
- setuptools-0.7-py2.3.egg - pip.egg-link
- setuptools.egg-link
- wheel.egg-link
d zc.buildout-1.0-py2.3.egg d zc.buildout-1.0-py2.3.egg
If we run the buildout on the default online and newest modes, If we run the buildout on the default online and newest modes,
...@@ -282,7 +286,9 @@ Then we'll get a new demo egg: ...@@ -282,7 +286,9 @@ Then we'll get a new demo egg:
d demo-0.2-py2.3.egg d demo-0.2-py2.3.egg
d demo-0.3-py2.3.egg d demo-0.3-py2.3.egg
d demoneeded-1.1-py2.3.egg d demoneeded-1.1-py2.3.egg
- setuptools-0.7-py2.4.egg - pip.egg-link
- setuptools.egg-link
- wheel.egg-link
d zc.buildout-1.0-py2.4.egg d zc.buildout-1.0-py2.4.egg
The script is updated too: The script is updated too:
......
...@@ -229,13 +229,11 @@ We won't get an update. ...@@ -229,13 +229,11 @@ We won't get an update.
- zc.recipe.egg.egg-link - zc.recipe.egg.egg-link
But if we run the buildout in the default on-line and newest modes, we But if we run the buildout in the default on-line and newest modes, we
will. This time we also get the test-variable message again, because the new will.
version is imported:
>>> print_(system(buildout), end='') # doctest: +ELLIPSIS >>> print_(system(buildout), end='') # doctest: +ELLIPSIS
Develop: '/sample-buildout/demo' Develop: '/sample-buildout/demo'
Updating extdemo. Updating extdemo.
zip_safe flag not set; analyzing archive contents...
Updating demo. Updating demo.
... ...
...@@ -341,17 +339,22 @@ Create our buildout: ...@@ -341,17 +339,22 @@ Create our buildout:
... recipe = recipes:environ ... recipe = recipes:environ
... ...
... """ % dict(server=link_server)) ... """ % dict(server=link_server))
>>> print_(system(buildout), end='') # doctest: +ELLIPSIS >>> print_(system(buildout+' -vvv'), end='') # doctest: +ELLIPSIS
Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
...
Develop: '/sample-buildout/recipes' Develop: '/sample-buildout/recipes'
...
Uninstalling demo. Uninstalling demo.
...
Uninstalling extdemo. Uninstalling extdemo.
...
Installing extdemo. Installing extdemo.
Have environment test-variable: foo ...
zip_safe flag not set; analyzing archive contents...
Installing checkenv. Installing checkenv.
...Running command python setup.py egg_info
...Have environment test-variable: foo
... ...
The setup.py also printed out that we have set the environment `test-variable` The setup.py also printed out that we have set the environment `test-variable`
to foo. After the buildout the variable is reset to its original value (i.e. to foo. After the buildout the variable is reset to its original value (i.e.
removed). removed).
...@@ -395,13 +398,18 @@ are interpolated with os.environ before the're set: ...@@ -395,13 +398,18 @@ are interpolated with os.environ before the're set:
... recipe = recipes:environ ... recipe = recipes:environ
... ...
... """ % dict(server=link_server)) ... """ % dict(server=link_server))
>>> print_(system(buildout), end='') # doctest: +ELLIPSIS >>> print_(system(buildout+' -vvv'), end='') # doctest: +ELLIPSIS
Installing 'zc.buildout', 'setuptools', 'pip', 'wheel'.
...
Develop: '/sample-buildout/recipes' Develop: '/sample-buildout/recipes'
...
Uninstalling extdemo. Uninstalling extdemo.
...
Installing extdemo. Installing extdemo.
Have environment test-variable: foo:bar ...
zip_safe flag not set; analyzing archive contents...
Updating checkenv. Updating checkenv.
...Running command python setup.py egg_info
...Have environment test-variable: foo:bar
... ...
>>> os.environ['test-variable'] >>> os.environ['test-variable']
......
...@@ -50,10 +50,10 @@ def test_suite(): ...@@ -50,10 +50,10 @@ def test_suite():
zc.buildout.tests.normalize_bang, zc.buildout.tests.normalize_bang,
zc.buildout.tests.normalize_S, zc.buildout.tests.normalize_S,
zc.buildout.testing.not_found, zc.buildout.testing.not_found,
zc.buildout.testing.easy_install_deprecated,
(re.compile(r'[d-] zc.buildout(-\S+)?[.]egg(-link)?'), (re.compile(r'[d-] zc.buildout(-\S+)?[.]egg(-link)?'),
'zc.buildout.egg'), 'zc.buildout.egg'),
(re.compile(r'[d-] setuptools-[^-]+-'), 'setuptools-X-'), (re.compile(r'[d-] setuptools-[^-]+-'), 'setuptools-X-'),
(re.compile(r'[d-] pip-[^-]+-'), 'pip-X-'),
(re.compile(r'eggs\\\\demo'), 'eggs/demo'), (re.compile(r'eggs\\\\demo'), 'eggs/demo'),
(re.compile(r'[a-zA-Z]:\\\\foo\\\\bar'), '/foo/bar'), (re.compile(r'[a-zA-Z]:\\\\foo\\\\bar'), '/foo/bar'),
]) ])
...@@ -66,7 +66,6 @@ def test_suite(): ...@@ -66,7 +66,6 @@ def test_suite():
zc.buildout.testing.normalize_path, zc.buildout.testing.normalize_path,
zc.buildout.testing.normalize_endings, zc.buildout.testing.normalize_endings,
zc.buildout.testing.not_found, zc.buildout.testing.not_found,
zc.buildout.testing.easy_install_deprecated,
(re.compile('__buildout_signature__ = ' (re.compile('__buildout_signature__ = '
r'sample-\S+\s+' r'sample-\S+\s+'
r'zc.recipe.egg-\S+\s+' r'zc.recipe.egg-\S+\s+'
...@@ -88,28 +87,9 @@ def test_suite(): ...@@ -88,28 +87,9 @@ def test_suite():
zc.buildout.testing.normalize_path, zc.buildout.testing.normalize_path,
zc.buildout.testing.normalize_endings, zc.buildout.testing.normalize_endings,
zc.buildout.testing.not_found, zc.buildout.testing.not_found,
zc.buildout.testing.easy_install_deprecated,
(re.compile("(d ((ext)?demo(needed)?|other)" (re.compile("(d ((ext)?demo(needed)?|other)"
r"-\d[.]\d-py)\d[.]\d(-\S+)?[.]egg"), r"-\d[.]\d-py)\d[.]\d(-\S+)?[.]egg"),
'\\1V.V.egg'), '\\1V.V.egg'),
(re.compile('extdemo.c\n.+\\\\extdemo.exp\n'), ''),
(re.compile(
r'zip_safe flag not set; analyzing archive contents.*\n'),
''),
(re.compile(
r'\n.*module references __file__'),
''),
(re.compile(''), ''),
(re.compile(
"extdemo[.]c\n"
"extdemo[.]obj : warning LNK4197: "
"export 'initextdemo' specified multiple times; "
"using first specification\n"
" Creating library build\\\\temp[.]win-amd64-2[.]"
"[4567]\\\\Release\\\\extdemo[.]lib and object "
"build\\\\temp[.]win-amd64-2[.][4567]\\\\Re"
"lease\\\\extdemo[.]exp\n"),
''),
]), ]),
), ),
doctest.DocFileSuite( doctest.DocFileSuite(
...@@ -120,7 +100,6 @@ def test_suite(): ...@@ -120,7 +100,6 @@ def test_suite():
zc.buildout.testing.normalize_path, zc.buildout.testing.normalize_path,
zc.buildout.testing.normalize_endings, zc.buildout.testing.normalize_endings,
zc.buildout.testing.not_found, zc.buildout.testing.not_found,
zc.buildout.testing.easy_install_deprecated,
]) ])
), ),
)) ))
......
...@@ -33,7 +33,7 @@ Here's an example: ...@@ -33,7 +33,7 @@ Here's an example:
>>> isinstance(ws, pkg_resources.WorkingSet) >>> isinstance(ws, pkg_resources.WorkingSet)
True True
>>> sorted(dist.project_name for dist in ws) >>> sorted(dist.project_name for dist in ws)
['demo', 'demoneeded', 'setuptools', 'zc.buildout', 'zc.recipe.egg'] ['demo', 'demoneeded', 'pip', 'setuptools', 'wheel', 'zc.buildout', 'zc.recipe.egg']
We'll monkey patch a method in the ``easy_install`` module in order to verify if We'll monkey patch a method in the ``easy_install`` module in order to verify if
the cache is working: the cache is working:
......
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