summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPreston Holmes <preston@ptone.com>2012-03-13 20:26:28 -0700
committerPreston Holmes <preston@ptone.com>2012-03-13 20:26:28 -0700
commit2b0067a46ae1ad4e8798ed5a86fbbe8e2b831341 (patch)
treec0617c8c6a09048397815a8b95b16c435fd4197d
parente53fda893c8170d9744df07471802bc8f97e5eda (diff)
downloaddisutils2-2b0067a46ae1ad4e8798ed5a86fbbe8e2b831341.tar.gz
fix for 14294
-rw-r--r--distutils2/database.py78
-rw-r--r--distutils2/tests/requires.txt15
-rw-r--r--distutils2/tests/test_util.py12
-rw-r--r--distutils2/util.py77
4 files changed, 112 insertions, 70 deletions
diff --git a/distutils2/database.py b/distutils2/database.py
index 9c5e682..6fb30ce 100644
--- a/distutils2/database.py
+++ b/distutils2/database.py
@@ -15,6 +15,7 @@ from distutils2 import logger
from distutils2.errors import PackagingError
from distutils2.version import suggest_normalized_version, VersionPredicate
from distutils2.metadata import Metadata
+from distutils2.util import parse_requires
__all__ = [
@@ -300,11 +301,6 @@ class EggInfoDistribution(object):
"""A :class:`distutils2.metadata.Metadata` instance loaded with
the distribution's ``METADATA`` file."""
- _REQUIREMENT = re.compile(
- r'(?P<name>[-A-Za-z0-9_.]+)\s*'
- r'(?P<first>(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)?\s*'
- r'(?P<rest>(?:\s*,\s*(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)*)\s*'
- r'(?P<extras>\[.*\])?')
def __init__(self, path):
self.path = path
@@ -314,20 +310,7 @@ class EggInfoDistribution(object):
self.version = self.metadata['Version']
return
- # reused from Distribute's pkg_resources
- def yield_lines(strs):
- """Yield non-empty/non-comment lines of a ``basestring``
- or sequence"""
- if isinstance(strs, basestring):
- for s in strs.splitlines():
- s = s.strip()
- # skip blank lines/comments
- if s and not s.startswith('#'):
- yield s
- else:
- for ss in strs:
- for s in yield_lines(ss):
- yield s
+
requires = None
@@ -335,15 +318,8 @@ class EggInfoDistribution(object):
if os.path.isdir(path):
meta_path = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
self.metadata = Metadata(path=meta_path)
- try:
- req_path = os.path.join(path, 'EGG-INFO', 'requires.txt')
- fp = open(req_path, 'r')
- try:
- requires = fp.read()
- finally:
- fp.close()
- except IOError:
- requires = None
+ req_path = os.path.join(path, 'EGG-INFO', 'requires.txt')
+ requires = parse_requires(req_path)
else:
# FIXME handle the case where zipfile is not available
zipf = zipimport.zipimporter(path)
@@ -360,14 +336,8 @@ class EggInfoDistribution(object):
elif path.endswith('.egg-info'):
if os.path.isdir(path):
path = os.path.join(path, 'PKG-INFO')
- try:
- fp = open(os.path.join(path, 'requires.txt'), 'r')
- try:
- requires = fp.read()
- finally:
- fp.close()
- except IOError:
- requires = None
+ req_path = os.path.join(path, 'requires.txt')
+ requires = parse_requires(req_path)
self.metadata = Metadata(path=path)
self.name = self.metadata['Name']
self.version = self.metadata['Version']
@@ -383,40 +353,10 @@ class EggInfoDistribution(object):
if field in self.metadata:
del self.metadata[field]
- reqs = []
- if requires is not None:
- for line in yield_lines(requires):
- if line.startswith('['):
- logger.warning(
- 'extensions in requires.txt are not supported '
- '(used by %r %s)', self.name, self.version)
- break
- else:
- match = self._REQUIREMENT.match(line.strip())
- if not match:
- # this happens when we encounter extras; since they
- # are written at the end of the file we just exit
- break
- else:
- if match.group('extras'):
- msg = ('extra requirements are not supported '
- '(used by %r %s)', self.name, self.version)
- logger.warning(msg, self.name)
- name = match.group('name')
- version = None
- if match.group('first'):
- version = match.group('first')
- if match.group('rest'):
- version += match.group('rest')
- version = version.replace(' ', '') # trim spaces
- if version is None:
- reqs.append(name)
- else:
- reqs.append('%s (%s)' % (name, version))
-
- if len(reqs) > 0:
- self.metadata['Requires-Dist'] += reqs
+
+ if requires is not None and len(requires)>0:
+ self.metadata['Requires-Dist'] += requires
if _cache_enabled:
_cache_path_egg[self.path] = self
diff --git a/distutils2/tests/requires.txt b/distutils2/tests/requires.txt
new file mode 100644
index 0000000..cc09961
--- /dev/null
+++ b/distutils2/tests/requires.txt
@@ -0,0 +1,15 @@
+setuptools
+zope.browser
+zope.component
+zope.configuration
+zope.contenttype >= 3.5
+zope.event
+zope.exceptions
+zope.i18n
+zope.interface
+zope.location
+zope.proxy
+zope.security
+
+[test]
+zope.testing \ No newline at end of file
diff --git a/distutils2/tests/test_util.py b/distutils2/tests/test_util.py
index 8d3e35e..95bc50f 100644
--- a/distutils2/tests/test_util.py
+++ b/distutils2/tests/test_util.py
@@ -18,7 +18,8 @@ from distutils2.util import (
get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages,
spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob,
RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging,
- get_install_method, cfg_to_args, generate_setup_py, encode_multipart)
+ get_install_method, cfg_to_args, generate_setup_py, encode_multipart,
+ parse_requires)
from distutils2.tests import support, unittest
from distutils2.tests.test_config import SETUP_CFG
@@ -378,6 +379,15 @@ class UtilTestCase(support.EnvironRestorer,
self.assertEqual(sorted(res),
['pkg1', 'pkg1.pkg3', 'pkg1.pkg3.pkg6', 'pkg5'])
+ def test_parse_requires(self):
+ req_file = os.path.join(os.path.dirname(__file__), 'requires.txt')
+ expected_requires = ['setuptools', 'zope.browser', 'zope.component',
+ 'zope.configuration', 'zope.contenttype', 'zope.event',
+ 'zope.exceptions', 'zope.i18n', 'zope.interface',
+ 'zope.location', 'zope.proxy', 'zope.security']
+ requires = parse_requires(req_file)
+ self.assertEqual(requires, expected_requires)
+
def test_resolve_name(self):
# test raw module name
tmpdir = self.mkdtemp()
diff --git a/distutils2/util.py b/distutils2/util.py
index aa5b3c3..4281de0 100644
--- a/distutils2/util.py
+++ b/distutils2/util.py
@@ -25,6 +25,7 @@ from distutils2 import logger
from distutils2.errors import (PackagingPlatformError, PackagingFileError,
PackagingExecError, InstallationException,
PackagingInternalError)
+from distutils2.metadata import Metadata
from distutils2._backport import shutil, sysconfig
__all__ = [
@@ -1172,6 +1173,71 @@ def _write_record_file(record_path, installed_files):
f.close()
return record_path
+def parse_requires(req_path):
+ """Takes the raw content of a requires.txt file and returns a list of requirements"""
+
+ # reused from Distribute's pkg_resources
+ def yield_lines(strs):
+ """Yield non-empty/non-comment lines of a ``basestring``
+ or sequence"""
+ if isinstance(strs, basestring):
+ for s in strs.splitlines():
+ s = s.strip()
+ # skip blank lines/comments
+ if s and not s.startswith('#'):
+ yield s
+ else:
+ for ss in strs:
+ for s in yield_lines(ss):
+ yield s
+
+ _REQUIREMENT = re.compile(
+ r'(?P<name>[-A-Za-z0-9_.]+)\s*'
+ r'(?P<first>(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)?\s*'
+ r'(?P<rest>(?:\s*,\s*(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)*)\s*'
+ r'(?P<extras>\[.*\])?')
+
+ reqs = []
+ try:
+ fp = open(req_path, 'r')
+ try:
+ requires = fp.read()
+ finally:
+ fp.close()
+ except IOError:
+ return None
+
+ for line in yield_lines(requires):
+ if line.startswith('['):
+ logger.warning('extensions in requires.txt are not supported')
+ break
+ else:
+ match = _REQUIREMENT.match(line.strip())
+ if not match:
+ # this happens when we encounter extras; since they
+ # are written at the end of the file we just exit
+ break
+ else:
+ if match.group('extras'):
+ # msg = ('extra requirements are not supported '
+ # '(used by %r %s)', self.name, self.version)
+ msg = 'extra requirements are not supported'
+ logger.warning(msg)
+ name = match.group('name')
+ version = None
+ if match.group('first'):
+ version = match.group('first')
+ if match.group('rest'):
+ version += match.group('rest')
+ version = version.replace(' ', '') # trim spaces
+ if version is None:
+ reqs.append(name)
+ else:
+ reqs.append('%s (%s)' % (name, version))
+ return reqs
+
+
+
def egginfo_to_distinfo(record_file, installer=_DEFAULT_INSTALLER,
requested=False, remove_egginfo=False):
@@ -1201,6 +1267,17 @@ def egginfo_to_distinfo(record_file, installer=_DEFAULT_INSTALLER,
metadata_path = distinfo['metadata_path']
logger.info('creating %s', metadata_path)
shutil.copy2(distinfo['metadata'], metadata_path)
+ # add requirements and output metadata
+ requires = None
+ req_path = os.path.join(distinfo_dir, 'requires.txt')
+ requires = parse_requires(req_path)
+ if requires is not None:
+ # create a metadata instance to handle the reqs injection
+ metadata = Metadata(path=metadata_path)
+ metadata['Requires-Dist'] = requires
+ metadata.write(metadata_path)
+
+
installer_path = distinfo['installer_path']
logger.info('creating %s', installer_path)