Commit 4da195dc authored by PJ Eby's avatar PJ Eby

Implement dependency_links feature, courtesy of Tres Seaver's rough

draft of a patch.

--HG--
branch : setuptools
extra : convert_revision : svn%3A6015fed2-1504-0410-9fe1-9d1591cc4771/sandbox/trunk/setuptools%4043423
parent a8ab614c
...@@ -1089,6 +1089,9 @@ Known Issues ...@@ -1089,6 +1089,9 @@ Known Issues
time out or be missing a file. time out or be missing a file.
0.6a11 0.6a11
* Process ``dependency_links.txt`` if found in a distribution, by adding the
URLs to the list for scanning.
* Use relative paths in ``.pth`` files when eggs are being installed to the * Use relative paths in ``.pth`` files when eggs are being installed to the
same directory as the ``.pth`` file. This maximizes portability of the same directory as the ``.pth`` file. This maximizes portability of the
target directory when building applications that contain eggs. target directory when building applications that contain eggs.
......
...@@ -42,9 +42,7 @@ setup( ...@@ -42,9 +42,7 @@ setup(
packages = find_packages(), packages = find_packages(),
package_data = {'setuptools':['*.exe']}, package_data = {'setuptools':['*.exe']},
py_modules = ['pkg_resources', 'easy_install', 'site'], py_modules = ['pkg_resources', 'easy_install', 'site'],
zip_safe = False, # We want 'python -m easy_install' to work, for now :( zip_safe = False, # We want 'python -m easy_install' to work, for now :(
entry_points = { entry_points = {
"distutils.commands" : [ "distutils.commands" : [
"%(cmd)s = setuptools.command.%(cmd)s:%(cmd)s" % locals() "%(cmd)s = setuptools.command.%(cmd)s:%(cmd)s" % locals()
...@@ -62,15 +60,17 @@ setup( ...@@ -62,15 +60,17 @@ setup(
"package_data = setuptools.dist:check_package_data", "package_data = setuptools.dist:check_package_data",
"exclude_package_data = setuptools.dist:check_package_data", "exclude_package_data = setuptools.dist:check_package_data",
"include_package_data = setuptools.dist:assert_bool", "include_package_data = setuptools.dist:assert_bool",
"dependency_links = setuptools.dist:assert_string_list",
], ],
"egg_info.writers": [ "egg_info.writers": [
"PKG-INFO = setuptools.command.egg_info:write_pkg_info", "PKG-INFO = setuptools.command.egg_info:write_pkg_info",
"requires.txt = setuptools.command.egg_info:write_requirements", "requires.txt = setuptools.command.egg_info:write_requirements",
"entry_points.txt = setuptools.command.egg_info:write_entries", "entry_points.txt = setuptools.command.egg_info:write_entries",
"eager_resources.txt = setuptools.command.egg_info:write_arg", "eager_resources.txt = setuptools.command.egg_info:overwrite_arg",
"namespace_packages.txt = setuptools.command.egg_info:write_arg", "namespace_packages.txt = setuptools.command.egg_info:overwrite_arg",
"top_level.txt = setuptools.command.egg_info:write_toplevel_names", "top_level.txt = setuptools.command.egg_info:write_toplevel_names",
"depends.txt = setuptools.command.egg_info:warn_depends_obsolete", "depends.txt = setuptools.command.egg_info:warn_depends_obsolete",
"dependency_links.txt = setuptools.command.egg_info:overwrite_arg",
], ],
"console_scripts": "console_scripts":
["easy_install = setuptools.command.easy_install:main", ["easy_install = setuptools.command.easy_install:main",
......
[distutils.setup_keywords] [distutils.setup_keywords]
dependency_links = setuptools.dist:assert_string_list
entry_points = setuptools.dist:check_entry_points entry_points = setuptools.dist:check_entry_points
extras_require = setuptools.dist:check_extras extras_require = setuptools.dist:check_extras
package_data = setuptools.dist:check_package_data package_data = setuptools.dist:check_package_data
...@@ -12,11 +13,12 @@ zip_safe = setuptools.dist:assert_bool ...@@ -12,11 +13,12 @@ zip_safe = setuptools.dist:assert_bool
tests_require = setuptools.dist:check_requirements tests_require = setuptools.dist:check_requirements
[egg_info.writers] [egg_info.writers]
dependency_links.txt = setuptools.command.egg_info:overwrite_arg
requires.txt = setuptools.command.egg_info:write_requirements requires.txt = setuptools.command.egg_info:write_requirements
PKG-INFO = setuptools.command.egg_info:write_pkg_info PKG-INFO = setuptools.command.egg_info:write_pkg_info
eager_resources.txt = setuptools.command.egg_info:write_arg eager_resources.txt = setuptools.command.egg_info:overwrite_arg
top_level.txt = setuptools.command.egg_info:write_toplevel_names top_level.txt = setuptools.command.egg_info:write_toplevel_names
namespace_packages.txt = setuptools.command.egg_info:write_arg namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
entry_points.txt = setuptools.command.egg_info:write_entries entry_points.txt = setuptools.command.egg_info:write_entries
depends.txt = setuptools.command.egg_info:warn_depends_obsolete depends.txt = setuptools.command.egg_info:warn_depends_obsolete
......
...@@ -319,6 +319,13 @@ unless you need the associated ``setuptools`` feature. ...@@ -319,6 +319,13 @@ unless you need the associated ``setuptools`` feature.
when the setup script is run, you should add them to ``install_requires`` when the setup script is run, you should add them to ``install_requires``
**and** ``setup_requires``.) **and** ``setup_requires``.)
``dependency_links``
A list of strings naming URLs to be searched when satisfying dependencies.
These links will be used if needed to install packages specified by
``setup_requires`` or ``tests_require``. They will also be written into
the egg's metadata for use by tools like EasyInstall to use when installing
an ``.egg`` file.
``namespace_packages`` ``namespace_packages``
A list of strings naming the project's "namespace packages". A namespace A list of strings naming the project's "namespace packages". A namespace
package is a package that may be split across multiple project package is a package that may be split across multiple project
...@@ -2359,6 +2366,8 @@ Release Notes/Change History ...@@ -2359,6 +2366,8 @@ Release Notes/Change History
---------------------------- ----------------------------
0.6a11 0.6a11
* Added ``dependency_links`` to allow specifying URLs for ``--find-links``.
* Enhanced test loader to scan packages as well as modules, and call * Enhanced test loader to scan packages as well as modules, and call
``additional_tests()`` if present to get non-unittest tests. ``additional_tests()`` if present to get non-unittest tests.
......
...@@ -90,7 +90,7 @@ class easy_install(Command): ...@@ -90,7 +90,7 @@ class easy_install(Command):
self.optimize = self.record = None self.optimize = self.record = None
self.upgrade = self.always_copy = self.multi_version = None self.upgrade = self.always_copy = self.multi_version = None
self.editable = self.no_deps = self.allow_hosts = None self.editable = self.no_deps = self.allow_hosts = None
self.root = self.prefix = None self.root = self.prefix = self.no_report = None
# Options not specifiable via command line # Options not specifiable via command line
self.package_index = None self.package_index = None
...@@ -509,7 +509,10 @@ Please make the appropriate changes for your system and try again. ...@@ -509,7 +509,10 @@ Please make the appropriate changes for your system and try again.
requirement = Requirement( requirement = Requirement(
distreq.project_name, distreq.specs, requirement.extras distreq.project_name, distreq.specs, requirement.extras
) )
if dist.has_metadata('dependency_links.txt'):
self.package_index.add_find_links(
dist.get_metadata_lines('dependency_links.txt')
)
log.info("Processing dependencies for %s", requirement) log.info("Processing dependencies for %s", requirement)
try: try:
distros = WorkingSet([]).resolve( distros = WorkingSet([]).resolve(
...@@ -524,7 +527,6 @@ Please make the appropriate changes for your system and try again. ...@@ -524,7 +527,6 @@ Please make the appropriate changes for your system and try again.
"Installed distribution %s conflicts with requirement %s" "Installed distribution %s conflicts with requirement %s"
% e.args % e.args
) )
if self.always_copy: if self.always_copy:
# Force all the relevant distros to be copied or activated # Force all the relevant distros to be copied or activated
for dist in distros: for dist in distros:
...@@ -862,7 +864,7 @@ you ignore the conflicts, the installed package(s) may not work. ...@@ -862,7 +864,7 @@ you ignore the conflicts, the installed package(s) may not work.
def installation_report(self, req, dist, what="Installed"): def installation_report(self, req, dist, what="Installed"):
"""Helpful installation message for display to package users""" """Helpful installation message for display to package users"""
msg = "\n%(what)s %(eggloc)s%(extras)s" msg = "\n%(what)s %(eggloc)s%(extras)s"
if self.multi_version: if self.multi_version and not self.no_report:
msg += """ msg += """
Because this distribution was installed --multi-version or --install-dir, Because this distribution was installed --multi-version or --install-dir,
......
...@@ -80,19 +80,19 @@ class egg_info(Command): ...@@ -80,19 +80,19 @@ class egg_info(Command):
def write_or_delete_file(self, what, filename, data): def write_or_delete_file(self, what, filename, data, force=False):
"""Write `data` to `filename` or delete if empty """Write `data` to `filename` or delete if empty
If `data` is non-empty, this routine is the same as ``write_file()``. If `data` is non-empty, this routine is the same as ``write_file()``.
If `data` is empty but not ``None``, this is the same as calling If `data` is empty but not ``None``, this is the same as calling
``delete_file(filename)`. If `data` is ``None``, then this is a no-op ``delete_file(filename)`. If `data` is ``None``, then this is a no-op
unless `filename` exists, in which case a warning is issued about the unless `filename` exists, in which case a warning is issued about the
orphaned file. orphaned file (if `force` is false), or deleted (if `force` is true).
""" """
if data: if data:
self.write_file(what, filename, data) self.write_file(what, filename, data)
elif os.path.exists(filename): elif os.path.exists(filename):
if data is None: if data is None and not force:
log.warn( log.warn(
"%s not set in setup(), but %s exists", what, filename "%s not set in setup(), but %s exists", what, filename
) )
...@@ -326,12 +326,15 @@ def write_toplevel_names(cmd, basename, filename): ...@@ -326,12 +326,15 @@ def write_toplevel_names(cmd, basename, filename):
def write_arg(cmd, basename, filename): def overwrite_arg(cmd, basename, filename):
write_arg(cmd, basename, filename, True)
def write_arg(cmd, basename, filename, force=False):
argname = os.path.splitext(basename)[0] argname = os.path.splitext(basename)[0]
value = getattr(cmd.distribution, argname, None) value = getattr(cmd.distribution, argname, None)
if value is not None: if value is not None:
value = '\n'.join(value)+'\n' value = '\n'.join(value)+'\n'
cmd.write_or_delete_file(argname, filename, value) cmd.write_or_delete_file(argname, filename, value, force)
def write_entries(cmd, basename, filename): def write_entries(cmd, basename, filename):
ep = cmd.distribution.entry_points ep = cmd.distribution.entry_points
...@@ -347,7 +350,7 @@ def write_entries(cmd, basename, filename): ...@@ -347,7 +350,7 @@ def write_entries(cmd, basename, filename):
data.append('[%s]\n%s\n\n' % (section,contents)) data.append('[%s]\n%s\n\n' % (section,contents))
data = ''.join(data) data = ''.join(data)
cmd.write_or_delete_file('entry points', filename, data) cmd.write_or_delete_file('entry points', filename, data, True)
def get_pkg_info_revision(): def get_pkg_info_revision():
# See if we can get a -r### off of PKG-INFO, in case this is an sdist of # See if we can get a -r### off of PKG-INFO, in case this is an sdist of
...@@ -364,6 +367,3 @@ def get_pkg_info_revision(): ...@@ -364,6 +367,3 @@ def get_pkg_info_revision():
...@@ -211,16 +211,16 @@ class Distribution(_Distribution): ...@@ -211,16 +211,16 @@ class Distribution(_Distribution):
self.features = {} self.features = {}
self.dist_files = [] self.dist_files = []
self.patch_missing_pkg_info(attrs) self.patch_missing_pkg_info(attrs)
# Make sure we have any eggs needed to interpret 'attrs'
if attrs and 'dependency_links' in attrs:
self.dependency_links = attrs.pop('dependency_links')
assert_string_list(self,'dependency_links',self.dependency_links)
if attrs and 'setup_requires' in attrs: if attrs and 'setup_requires' in attrs:
# Make sure we have any eggs needed to interpret 'attrs'
self.fetch_build_eggs(attrs.pop('setup_requires')) self.fetch_build_eggs(attrs.pop('setup_requires'))
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
if not hasattr(self,ep.name): if not hasattr(self,ep.name):
setattr(self,ep.name,None) setattr(self,ep.name,None)
_Distribution.__init__(self,attrs) _Distribution.__init__(self,attrs)
if isinstance(self.metadata.version, (int,long,float)): if isinstance(self.metadata.version, (int,long,float)):
# Some people apparently take "version number" too literally :) # Some people apparently take "version number" too literally :)
self.metadata.version = str(self.metadata.version) self.metadata.version = str(self.metadata.version)
...@@ -246,7 +246,6 @@ class Distribution(_Distribution): ...@@ -246,7 +246,6 @@ class Distribution(_Distribution):
def finalize_options(self): def finalize_options(self):
_Distribution.finalize_options(self) _Distribution.finalize_options(self)
if self.features: if self.features:
self._set_global_opts_from_features() self._set_global_opts_from_features()
...@@ -256,7 +255,6 @@ class Distribution(_Distribution): ...@@ -256,7 +255,6 @@ class Distribution(_Distribution):
ep.require(installer=self.fetch_build_egg) ep.require(installer=self.fetch_build_egg)
ep.load()(self, ep.name, value) ep.load()(self, ep.name, value)
def fetch_build_egg(self, req): def fetch_build_egg(self, req):
"""Fetch an egg needed for building""" """Fetch an egg needed for building"""
try: try:
...@@ -273,18 +271,20 @@ class Distribution(_Distribution): ...@@ -273,18 +271,20 @@ class Distribution(_Distribution):
for key in opts.keys(): for key in opts.keys():
if key not in keep: if key not in keep:
del opts[key] # don't use any other settings del opts[key] # don't use any other settings
if self.dependency_links:
links = self.dependency_links[:]
if 'find_links' in opts:
links = opts['find_links'][1].split() + links
opts['find_links'] = ('setup', links)
cmd = easy_install( cmd = easy_install(
dist, args=["x"], install_dir=os.curdir, exclude_scripts=True, dist, args=["x"], install_dir=os.curdir, exclude_scripts=True,
always_copy=False, build_directory=None, editable=False, always_copy=False, build_directory=None, editable=False,
upgrade=False, multi_version=True upgrade=False, multi_version=True, no_report = True
) )
cmd.ensure_finalized() cmd.ensure_finalized()
self._egg_fetcher = cmd self._egg_fetcher = cmd
return cmd.easy_install(req) return cmd.easy_install(req)
def _set_global_opts_from_features(self): def _set_global_opts_from_features(self):
"""Add --with-X/--without-X options based on optional features""" """Add --with-X/--without-X options based on optional features"""
......
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