]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blobdiff - src/allmydata/__init__.py
Minor code cleanup in __init__.py.
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / __init__.py
index 7c5236335a3f278154448ada07c2d45b995c45c0..5262773ae3a419d016a4243f85ca03f3a6a249aa 100644 (file)
@@ -15,9 +15,19 @@ __version__ = "unknown"
 try:
     from allmydata._version import __version__
 except ImportError:
-    # We're running in a tree that hasn't run "./setup.py darcsver", and didn't
-    # come with a _version.py, so we don't know what our version is. This should
-    # not happen very often.
+    # We're running in a tree that hasn't run update_version, and didn't
+    # come with a _version.py, so we don't know what our version is.
+    # This should not happen very often.
+    pass
+
+full_version = "unknown"
+branch = "unknown"
+try:
+    from allmydata._version import full_version, branch
+except ImportError:
+    # We're running in a tree that hasn't run update_version, and didn't
+    # come with a _version.py, so we don't know what our full version or
+    # branch is. This should not happen very often.
     pass
 
 __appname__ = "unknown"
@@ -96,24 +106,25 @@ def get_linux_distro():
     if _distname and _version:
         return (_distname, _version)
 
-    try:
-        p = subprocess.Popen(["lsb_release", "--all"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        rc = p.wait()
-        if rc == 0:
-            for line in p.stdout.readlines():
-                m = _distributor_id_cmdline_re.search(line)
-                if m:
-                    _distname = m.group(1).strip()
-                    if _distname and _version:
-                        return (_distname, _version)
-
-                m = _release_cmdline_re.search(p.stdout.read())
-                if m:
-                    _version = m.group(1).strip()
-                    if _distname and _version:
-                        return (_distname, _version)
-    except EnvironmentError:
-        pass
+    if os.path.isfile("/usr/bin/lsb_release") or os.path.isfile("/bin/lsb_release"):
+        try:
+            p = subprocess.Popen(["lsb_release", "--all"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            rc = p.wait()
+            if rc == 0:
+                for line in p.stdout.readlines():
+                    m = _distributor_id_cmdline_re.search(line)
+                    if m:
+                        _distname = m.group(1).strip()
+                        if _distname and _version:
+                            return (_distname, _version)
+
+                    m = _release_cmdline_re.search(p.stdout.read())
+                    if m:
+                        _version = m.group(1).strip()
+                        if _distname and _version:
+                            return (_distname, _version)
+        except EnvironmentError:
+            pass
 
     if os.path.exists("/etc/arch-release"):
         return ("Arch_Linux", "")
@@ -141,11 +152,33 @@ 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
     from _auto_deps import package_imports, global_deprecation_messages, deprecation_messages, \
-        user_warning_messages, runtime_warning_messages, warning_imports
+        runtime_warning_messages, warning_imports
 
     def package_dir(srcfile):
         return os.path.dirname(os.path.dirname(os.path.normcase(os.path.realpath(srcfile))))
@@ -155,13 +188,13 @@ def get_package_versions_and_locations():
     # or any other bug that causes sys.path to be set up incorrectly. Therefore we
     # must import the packages in order to check their versions and paths.
 
-    # This is to suppress various DeprecationWarnings, UserWarnings, and RuntimeWarnings
+    # This is to suppress all UserWarnings and various DeprecationWarnings and RuntimeWarnings
     # (listed in _auto_deps.py).
 
+    warnings.filterwarnings("ignore", category=UserWarning, append=True)
+
     for msg in global_deprecation_messages + deprecation_messages:
         warnings.filterwarnings("ignore", category=DeprecationWarning, message=msg, append=True)
-    for msg in user_warning_messages:
-        warnings.filterwarnings("ignore", category=UserWarning, message=msg, append=True)
     for msg in runtime_warning_messages:
         warnings.filterwarnings("ignore", category=RuntimeWarning, message=msg, append=True)
     try:
@@ -171,14 +204,23 @@ def get_package_versions_and_locations():
             except ImportError:
                 pass
     finally:
-        # Leave suppressions for global_deprecation_messages active.
-        for ign in runtime_warning_messages + user_warning_messages + deprecation_messages:
+        # Leave suppressions for UserWarnings and global_deprecation_messages active.
+        for ign in runtime_warning_messages + deprecation_messages:
             warnings.filters.pop()
 
     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:
@@ -191,24 +233,27 @@ def get_package_versions_and_locations():
                 packages.append( (pkgname, (None, None, trace_info)) )
             else:
                 comment = None
-                if pkgname == 'setuptools' and hasattr(module, '_distribute'):
+                if pkgname == __appname__:
+                    comment = "%s: %s" % (branch, full_version)
+                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:
@@ -221,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()
@@ -268,10 +318,10 @@ def cross_check_pkg_resources_versus_import():
 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(), 'openssl']
 
     for name, (imp_ver, imp_loc, imp_comment) in imported_vers_and_locs_list:
         name = name.lower()
@@ -291,6 +341,12 @@ def cross_check(pkg_resources_vers_and_locs, imported_vers_and_locs_list):
                 continue
 
             pr_ver, pr_loc = pkg_resources_vers_and_locs[name]
+            if imp_ver is None and imp_loc is None:
+                errors.append("Warning: dependency %r could not be imported. pkg_resources thought it should be possible "
+                              "to import version %r from %r.\nThe exception trace was %r."
+                              % (name, pr_ver, pr_loc, imp_comment))
+                continue
+
             try:
                 pr_normver = normalized_version(pr_ver)
             except Exception, e:
@@ -321,12 +377,12 @@ def cross_check(pkg_resources_vers_and_locs, imported_vers_and_locs_list):
                                               % (name, pr_ver, str(pr_normver), pr_loc, imp_ver, str(imp_normver), imp_loc))
 
     imported_packages = set([p.lower() for (p, _) in imported_vers_and_locs_list])
+    extra_vers_and_locs_list = []
     for pr_name, (pr_ver, pr_loc) in pkg_resources_vers_and_locs.iteritems():
         if pr_name not in imported_packages and pr_name not in ignorable:
-            errors.append("Warning: dependency %r (version %r) found by pkg_resources not found by import."
-                          % (pr_name, pr_ver))
+            extra_vers_and_locs_list.append( (pr_name, (pr_ver, pr_loc, "according to pkg_resources")) )
 
-    return errors
+    return errors, extra_vers_and_locs_list
 
 
 def get_error_string(errors, debug=False):
@@ -351,14 +407,14 @@ def check_all_requirements():
 
     errors = []
 
-    # We require at least 2.5 on all platforms.
+    # We require at least 2.6 on all platforms.
     # (On Python 3, we'll have failed long before this point.)
-    if sys.version_info < (2, 5):
+    if sys.version_info < (2, 6):
         try:
             version_string = ".".join(map(str, sys.version_info))
         except Exception:
             version_string = repr(sys.version_info)
-        errors.append("Tahoe-LAFS current requires Python v2.5 or greater (but less than v3), not %s"
+        errors.append("Tahoe-LAFS currently requires Python v2.6 or greater (but less than v3), not %s"
                       % (version_string,))
 
     vers_and_locs = dict(_vers_and_locs_list)
@@ -381,6 +437,12 @@ def get_package_locations():
     return dict([(k, l) for k, (v, l, c) in _vers_and_locs_list])
 
 def get_package_versions_string(show_paths=False, debug=False):
+    errors = []
+    if not hasattr(sys, 'frozen'):
+        global _vers_and_locs_list
+        errors, extra_vers_and_locs_list = cross_check_pkg_resources_versus_import()
+        _vers_and_locs_list += extra_vers_and_locs_list
+
     res = []
     for p, (v, loc, comment) in _vers_and_locs_list:
         info = str(p) + ": " + str(v)
@@ -392,9 +454,7 @@ def get_package_versions_string(show_paths=False, debug=False):
 
     output = "\n".join(res) + "\n"
 
-    if not hasattr(sys, 'frozen'):
-        errors = cross_check_pkg_resources_versus_import()
-        if errors:
-            output += get_error_string(errors, debug=debug)
+    if errors:
+        output += get_error_string(errors, debug=debug)
 
     return output