]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blobdiff - src/allmydata/__init__.py
Add OpenSSL version check and tests. refs ticket:2215
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / __init__.py
index e7697e65fb7d16462a3121d264f22629e2db2e3e..5f6cd8c11f2f948d77bde72539125ca26a29c5dc 100644 (file)
@@ -152,6 +152,28 @@ def normalized_version(verstr, what=None):
         raise PackagingError, ("could not parse %s due to %s: %s"
                                % (what or repr(verstr), cls.__name__, value)), trace
 
+def get_openssl_version():
+    try:
+        from OpenSSL import SSL
+        return extract_openssl_version(SSL)
+    except Exception:
+        return ("unknown", None, None)
+
+def extract_openssl_version(ssl_module):
+    openssl_version = ssl_module.SSLeay_version(ssl_module.SSLEAY_VERSION)
+    if openssl_version.startswith('OpenSSL '):
+        openssl_version = openssl_version[8 :]
+
+    (version, _, comment) = openssl_version.partition(' ')
+
+    try:
+        openssl_cflags = ssl_module.SSLeay_version(ssl_module.SSLEAY_CFLAGS)
+        if '-DOPENSSL_NO_HEARTBEATS' in openssl_cflags.split(' '):
+            comment += ", no heartbeats"
+    except Exception:
+        pass
+
+    return (version, None, comment if comment else None)
 
 def get_package_versions_and_locations():
     import warnings
@@ -188,8 +210,17 @@ def get_package_versions_and_locations():
 
     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:
@@ -207,21 +238,22 @@ def get_package_versions_and_locations():
                 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':
             packages.append( (pkgname, (get_platform(), None, None)) )
+        elif pkgname == 'OpenSSL':
+            packages.append( (pkgname, get_openssl_version()) )
 
     return packages
 
 
 def check_requirement(req, vers_and_locs):
-    # TODO: check [] options
-    # We support only disjunctions of <=, >=, and ==
+    # We support only conjunctions 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:
@@ -234,33 +266,38 @@ def check_requirement(req, vers_and_locs):
         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()
@@ -284,7 +321,7 @@ def cross_check(pkg_resources_vers_and_locs, imported_vers_and_locs_list):
     from _auto_deps import not_import_versionable, ignorable
 
     errors = []
-    not_pkg_resourceable = ['python', 'platform', __appname__.lower()]
+    not_pkg_resourceable = ['python', 'platform', __appname__.lower(), 'openssl']
 
     for name, (imp_ver, imp_loc, imp_comment) in imported_vers_and_locs_list:
         name = name.lower()