diff options
author | Preston Holmes <preston@ptone.com> | 2012-03-13 20:26:28 -0700 |
---|---|---|
committer | Preston Holmes <preston@ptone.com> | 2012-03-13 20:26:28 -0700 |
commit | 2b0067a46ae1ad4e8798ed5a86fbbe8e2b831341 (patch) | |
tree | c0617c8c6a09048397815a8b95b16c435fd4197d | |
parent | e53fda893c8170d9744df07471802bc8f97e5eda (diff) | |
download | disutils2-2b0067a46ae1ad4e8798ed5a86fbbe8e2b831341.tar.gz |
fix for 14294
-rw-r--r-- | distutils2/database.py | 78 | ||||
-rw-r--r-- | distutils2/tests/requires.txt | 15 | ||||
-rw-r--r-- | distutils2/tests/test_util.py | 12 | ||||
-rw-r--r-- | distutils2/util.py | 77 |
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) |