diff -Nuar -Naur allmydata-tahoe-1.10.0.post26-old/setuptools-0.6c16dev4.egg/pkg_resources.py allmydata-tahoe-1.10.0.post26-new/setuptools-0.6c16dev4.egg/pkg_resources.py --- allmydata-tahoe-1.10.0.post26-old/setuptools-0.6c16dev4.egg/pkg_resources.py 2013-06-26 11:50:48.000000000 -0400 +++ allmydata-tahoe-1.10.0.post26-new/setuptools-0.6c16dev4.egg/pkg_resources.py 2015-06-10 18:22:49.197090458 -0400 @@ -527,14 +527,19 @@ # If we have a __requires__ then we can already tell if this # dist is unsatisfactory, in which case we won't add it. if __requires__ is not None: - for thisreqstr in __requires__: + if isinstance(__requires__, basestring): + array_of__requires__ = [__requires__] + else: + array_of__requires__ = __requires__ + + for thisreqstr in array_of__requires__: try: for thisreq in parse_requirements(thisreqstr): if thisreq.key == dist.key: if dist not in thisreq: return except ValueError, e: - e.args = tuple(e.args + ({'thisreqstr': thisreqstr},)) + e.args = tuple(e.args + ({'thisreqstr': thisreqstr, '__requires__': __requires__},)) raise self.by_key[dist.key] = dist diff -Nuar -Naur allmydata-tahoe-1.10.0.post26-old/src/allmydata/_auto_deps.py allmydata-tahoe-1.10.0.post26-new/src/allmydata/_auto_deps.py --- allmydata-tahoe-1.10.0.post26-old/src/allmydata/_auto_deps.py 2013-06-26 11:50:48.000000000 -0400 +++ allmydata-tahoe-1.10.0.post26-new/src/allmydata/_auto_deps.py 2015-06-10 19:22:46.464853667 -0400 @@ -16,7 +16,7 @@ # zope.interface >= 3.6.0 is required for Twisted >= 12.1.0. # zope.interface 3.6.3 and 3.6.4 are incompatible with Nevow (#1435). - "zope.interface == 3.6.0, == 3.6.1, == 3.6.2, >= 3.6.5", + "zope.interface >= 3.6.0, != 3.6.3, != 3.6.4", # * On Windows we need at least Twisted 9.0 to avoid an indirect # dependency on pywin32. @@ -48,15 +48,19 @@ # library, we need to update this declaration here. # "foolscap >= 0.6.3", - "pyOpenSSL", + "pyOpenSSL >= 0.13", - "Nevow >= 0.6.0", + "Nevow >= 0.9.33", + + "service-identity", # this is needed to suppress complaints about being unable to verify certs + "characteristic >= 14.0.0", # latest service-identity depends on this version + "pyasn1 >= 0.1.4", # latest pyasn1-modules depends on this version + "pyasn1-modules", # service-identity depends on this # Needed for SFTP. pyasn1 is needed by twisted.conch in Twisted >= 9.0. # pycrypto 2.2 doesn't work due to https://bugs.launchpad.net/pycrypto/+bug/620253 # pycrypto 2.4 doesn't work due to https://bugs.launchpad.net/pycrypto/+bug/881130 - "pycrypto == 2.1.0, == 2.3, >= 2.4.1", - "pyasn1 >= 0.0.8a", + "pycrypto >= 2.1.0, != 2.2, != 2.4", # http://www.voidspace.org.uk/python/mock/ , 0.8.0 provides "call" "mock >= 0.8.0", @@ -85,6 +89,35 @@ ('pycrypto', 'Crypto'), ('pyasn1', 'pyasn1'), ('mock', 'mock'), + ('service-identity', 'service_identity'), + ('characteristic', 'characteristic'), + ('pyasn1-modules', 'pyasn1_modules'), + ('cryptography', 'cryptography'), + ('cffi', 'cffi'), + ('six', 'six'), + ('enum34', 'enum'), + ('pycparser', 'pycparser'), +] + +# Dependencies for which we don't know how to get a version number at run-time. +not_import_versionable = [ + 'zope.interface', + 'mock', + 'pyasn1', + 'pyasn1-modules', +] + +# Dependencies reported by pkg_resources that we can safely ignore. +ignorable = [ + 'ipaddress', + 'idna', + 'argparse', + 'pyutil', + 'zbase32', + 'distribute', + 'twisted-web', + 'twisted-core', + 'twisted-conch', ] def require_more(): diff -Nuar -Naur allmydata-tahoe-1.10.0.post26-old/src/allmydata/__init__.py allmydata-tahoe-1.10.0.post26-new/src/allmydata/__init__.py --- allmydata-tahoe-1.10.0.post26-old/src/allmydata/__init__.py 2013-06-26 11:50:48.000000000 -0400 +++ allmydata-tahoe-1.10.0.post26-new/src/allmydata/__init__.py 2015-06-10 19:11:10.147772871 -0400 @@ -187,8 +187,17 @@ packages = [] - def get_version(module, attr): - return str(getattr(module, attr, 'unknown')) + def get_version(module): + if hasattr(module, '__version__'): + return str(getattr(module, '__version__')) + elif hasattr(module, 'version'): + ver = getattr(module, 'version') + if isinstance(ver, tuple): + return '.'.join(map(str, ver)) + else: + return str(ver) + else: + return 'unknown' for pkgname, modulename in [(__appname__, 'allmydata')] + package_imports: if modulename: @@ -206,7 +215,7 @@ elif pkgname == 'setuptools' and hasattr(module, '_distribute'): # distribute does not report its version in any module variables comment = 'distribute' - packages.append( (pkgname, (get_version(module, '__version__'), package_dir(module.__file__), comment)) ) + packages.append( (pkgname, (get_version(module), package_dir(module.__file__), comment)) ) elif pkgname == 'python': packages.append( (pkgname, (platform.python_version(), sys.executable, None)) ) elif pkgname == 'platform': @@ -220,7 +229,7 @@ # We support only disjunctions of <=, >=, and == reqlist = req.split(',') - name = reqlist[0].split('<=')[0].split('>=')[0].split('==')[0].strip(' ').split('[')[0] + name = reqlist[0].split('<=')[0].split('>=')[0].split('!=')[0].strip(' ').split('[')[0] if name not in vers_and_locs: raise PackagingError("no version info for %s" % (name,)) if req.strip(' ') == name: @@ -233,33 +242,38 @@ return actualver = normalized_version(actual, what="actual version %r of %s from %r" % (actual, name, location)) + if not match_requirement(req, reqlist, actualver): + msg = ("We require %s, but could only find version %s.\n" % (req, actual)) + if location and location != 'unknown': + msg += "The version we found is from %r.\n" % (location,) + msg += ("To resolve this problem, uninstall that version, either using your\n" + "operating system's package manager or by moving aside the directory.") + raise PackagingError(msg) + + +def match_requirement(req, reqlist, actualver): for r in reqlist: s = r.split('<=') if len(s) == 2: required = s[1].strip(' ') - if actualver <= normalized_version(required, what="required maximum version %r in %r" % (required, req)): - return # maximum requirement met + if not (actualver <= normalized_version(required, what="required maximum version %r in %r" % (required, req))): + return False # maximum requirement not met else: s = r.split('>=') if len(s) == 2: required = s[1].strip(' ') - if actualver >= normalized_version(required, what="required minimum version %r in %r" % (required, req)): - return # minimum requirement met + if not (actualver >= normalized_version(required, what="required minimum version %r in %r" % (required, req))): + return False # minimum requirement not met else: - s = r.split('==') + s = r.split('!=') if len(s) == 2: required = s[1].strip(' ') - if actualver == normalized_version(required, what="required exact version %r in %r" % (required, req)): - return # exact requirement met + if not (actualver != normalized_version(required, what="excluded version %r in %r" % (required, req))): + return False # not-equal requirement not met else: raise PackagingError("no version info or could not understand requirement %r" % (req,)) - msg = ("We require %s, but could only find version %s.\n" % (req, actual)) - if location and location != 'unknown': - msg += "The version we found is from %r.\n" % (location,) - msg += ("To resolve this problem, uninstall that version, either using your\n" - "operating system's package manager or by moving aside the directory.") - raise PackagingError(msg) + return True _vers_and_locs_list = get_package_versions_and_locations() @@ -280,10 +294,10 @@ def cross_check(pkg_resources_vers_and_locs, imported_vers_and_locs_list): """This function returns a list of errors due to any failed cross-checks.""" + from _auto_deps import not_import_versionable, ignorable + errors = [] - not_pkg_resourceable = set(['python', 'platform', __appname__.lower()]) - not_import_versionable = set(['zope.interface', 'mock', 'pyasn1']) - ignorable = set(['argparse', 'pyutil', 'zbase32', 'distribute', 'twisted-web', 'twisted-core', 'twisted-conch']) + not_pkg_resourceable = ['python', 'platform', __appname__.lower()] for name, (imp_ver, imp_loc, imp_comment) in imported_vers_and_locs_list: name = name.lower() diff -Nuar -Naur allmydata-tahoe-1.10.0.post26-old/src/allmydata/test/test_version.py allmydata-tahoe-1.10.0.post26-new/src/allmydata/test/test_version.py --- allmydata-tahoe-1.10.0.post26-old/src/allmydata/test/test_version.py 2013-06-26 11:50:48.000000000 -0400 +++ allmydata-tahoe-1.10.0.post26-new/src/allmydata/test/test_version.py 2015-06-10 18:36:50.114719577 -0400 @@ -1,4 +1,5 @@ +from pkg_resources import Requirement from twisted.trial import unittest from allmydata import check_requirement, cross_check, PackagingError @@ -9,39 +10,45 @@ class CheckRequirement(unittest.TestCase): def test_check_requirement(self): - check_requirement("setuptools >= 0.6c6", {"setuptools": ("0.6", "", None)}) - check_requirement("setuptools >= 0.6c6", {"setuptools": ("0.6", "", "distribute")}) - check_requirement("pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.1.0", "", None)}) - check_requirement("pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.4.0", "", None)}) - check_requirement("zope.interface <= 3.6.2, >= 3.6.6", {"zope.interface": ("3.6.1", "", None)}) - check_requirement("zope.interface <= 3.6.2, >= 3.6.6", {"zope.interface": ("3.6.6", "", None)}) - - check_requirement("zope.interface", {"zope.interface": ("unknown", "", None)}) - check_requirement("mock", {"mock": ("0.6.0", "", None)}) - check_requirement("foo >= 1.0", {"foo": ("1.0", "", None), "bar": ("2.0", "", None)}) + self._check_success("setuptools >= 0.6c6", {"setuptools": ("0.6", "", None)}) + self._check_success("setuptools >= 0.6c6", {"setuptools": ("0.6", "", "distribute")}) + self._check_success("pycrypto >= 2.1.0, != 2.2, != 2.4", {"pycrypto": ("2.1.0", "", None)}) + self._check_success("pycrypto >= 2.1.0, != 2.2, != 2.4", {"pycrypto": ("2.3.0", "", None)}) + self._check_success("pycrypto >= 2.1.0, != 2.2, != 2.4", {"pycrypto": ("2.4.1", "", None)}) + + self._check_success("zope.interface", {"zope.interface": ("unknown", "", None)}) + self._check_success("mock", {"mock": ("0.6.0", "", None)}) + self._check_success("foo >= 1.0", {"foo": ("1.0", "", None), "bar": ("2.0", "", None)}) - check_requirement("foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.7.0", "", None)}) + self._check_success("foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.7.0", "", None)}) try: - check_requirement("foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.6.1+", "", None)}) + self._check_success("foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.6.1+", "", None)}) # succeeding is ok except PackagingError, e: self.failUnlessIn("could not parse", str(e)) - self.failUnlessRaises(PackagingError, check_requirement, - "foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.5.1", "", None)}) - self.failUnlessRaises(PackagingError, check_requirement, - "pycrypto == 2.0.1, == 2.1, >= 2.3", {"pycrypto": ("2.2.0", "", None)}) - self.failUnlessRaises(PackagingError, check_requirement, - "zope.interface <= 3.6.2, >= 3.6.6", {"zope.interface": ("3.6.4", "", None)}) - self.failUnlessRaises(PackagingError, check_requirement, - "foo >= 1.0", {}) - self.failUnlessRaises(PackagingError, check_requirement, - "foo >= 1.0", {"foo": ("irrational", "", None)}) + self._check_failure("foolscap[secure_connections] >= 0.6.0", {"foolscap": ("0.5.1", "", None)}) + self._check_failure("pycrypto >= 2.1.0, != 2.2, != 2.4", {"pycrypto": ("2.2.0", "", None)}) + self._check_failure("pycrypto >= 2.1.0, != 2.2, != 2.4", {"pycrypto": ("2.0.0", "", None)}) + self._check_failure("foo >= 1.0", {}) + self._check_failure("foo >= 1.0", {"foo": ("irrational", "", None)}) self.failUnlessRaises(ImportError, check_requirement, "foo >= 1.0", {"foo": (None, None, "foomodule")}) + def _check_success(self, req, vers_and_locs): + check_requirement(req, vers_and_locs) + + for pkg, ver in vers_and_locs.items(): + self.failUnless(ver[0] in Requirement.parse(req), str((ver, req))) + + def _check_failure(self, req, vers_and_locs): + self.failUnlessRaises(PackagingError, check_requirement, req, vers_and_locs) + + for pkg, ver in vers_and_locs.items(): + self.failIf(ver[0] in Requirement.parse(req), str((ver, req))) + def test_cross_check_ticket_1355(self): # The bug in #1355 is triggered when a version string from either pkg_resources or import # is not parseable at all by normalized_version.