From 9f8955ccdda2a8e30010895a655f39798bbad825 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 22 May 2018 14:16:13 +0300 Subject: [PATCH] Reused depends in checkdeps script and formatted it also, made checkdeps executable instead of depends --- checkdeps.py | 203 ++++++++------------------------ src/depends.py | 305 +++++++++++++++++++++++++++++-------------------- 2 files changed, 232 insertions(+), 276 deletions(-) mode change 100644 => 100755 checkdeps.py diff --git a/checkdeps.py b/checkdeps.py old mode 100644 new mode 100755 index 73e5994d..f261c924 --- a/checkdeps.py +++ b/checkdeps.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python2 """ Check dependendies and give recommendations about how to satisfy them @@ -9,112 +10,24 @@ Limitations: EXTRAS_REQUIRE. This is fine because most developers do, too. """ +import os from distutils.errors import CompileError try: from setuptools.dist import Distribution from setuptools.extension import Extension from setuptools.command.build_ext import build_ext HAVE_SETUPTOOLS = True + # another import from setuptools is in setup.py + from setup import EXTRAS_REQUIRE except ImportError: HAVE_SETUPTOOLS = False + EXTRAS_REQUIRE = [] + from importlib import import_module -import os -import sys -from setup import EXTRAS_REQUIRE +from src.depends import detectOS, PACKAGES, PACKAGE_MANAGER -PROJECT_ROOT = os.path.abspath('..') -sys.path.insert(0, PROJECT_ROOT) - -# OS-specific dependencies for optional components listed in EXTRAS_REQUIRE -EXTRAS_REQUIRE_DEPS = { - # The values from setup.EXTRAS_REQUIRE - 'python_prctl': { - # The packages needed for this requirement, by OS - "OpenBSD": [""], - "FreeBSD": [""], - "Debian": ["libcap-dev"], - "Ubuntu": [""], - "Ubuntu 12": [""], - "openSUSE": [""], - "Fedora": [""], - "Guix": [""], - "Gentoo": [""], - }, -} - -PACKAGE_MANAGER = { - "OpenBSD": "pkg_add", - "FreeBSD": "pkg install", - "Debian": "apt-get install", - "Ubuntu": "apt-get install", - "Ubuntu 12": "apt-get install", - "openSUSE": "zypper install", - "Fedora": "dnf install", - "Guix": "guix package -i", - "Gentoo": "emerge" -} - -PACKAGES = { - "PyQt4": { - "OpenBSD": "py-qt4", - "FreeBSD": "py27-qt4", - "Debian": "python-qt4", - "Ubuntu": "python-qt4", - "Ubuntu 12": "python-qt4", - "openSUSE": "python-qt", - "Fedora": "PyQt4", - "Guix": "python2-pyqt@4.11.4", - "Gentoo": "dev-python/PyQt4", - 'optional': True, - 'description': "You only need PyQt if you want to use the GUI. " \ - "When only running as a daemon, this can be skipped.\n" \ - "However, you would have to install it manually " \ - "because setuptools does not support PyQt." - }, - "msgpack": { - "OpenBSD": "py-msgpack", - "FreeBSD": "py27-msgpack-python", - "Debian": "python-msgpack", - "Ubuntu": "python-msgpack", - "Ubuntu 12": "msgpack-python", - "openSUSE": "python-msgpack-python", - "Fedora": "python2-msgpack", - "Guix": "python2-msgpack", - "Gentoo": "dev-python/msgpack", - "optional": True, - "description": "python-msgpack is recommended for improved performance of message encoding/decoding" - }, - "pyopencl": { - "FreeBSD": "py27-pyopencl", - "Debian": "python-pyopencl", - "Ubuntu": "python-pyopencl", - "Ubuntu 12": "python-pyopencl", - "Fedora": "python2-pyopencl", - "openSUSE": "", - "OpenBSD": "", - "Guix": "", - "Gentoo": "dev-python/pyopencl", - "optional": True, - 'description': "If you install pyopencl, you will be able to use " \ - "GPU acceleration for proof of work. \n" \ - "You also need a compatible GPU and drivers." - }, - "setuptools": { - "OpenBSD": "py-setuptools", - "FreeBSD": "py27-setuptools", - "Debian": "python-setuptools", - "Ubuntu": "python-setuptools", - "Ubuntu 12": "python-setuptools", - "Fedora": "python2-setuptools", - "openSUSE": "python-setuptools", - "Guix": "python2-setuptools", - "Gentoo": "", - "optional": False, - } -} - COMPILING = { "Debian": "build-essential libssl-dev", "Ubuntu": "build-essential libssl-dev", @@ -123,46 +36,23 @@ COMPILING = { "optional": False, } -def detectOSRelease(): - with open("/etc/os-release", 'r') as osRelease: - version = None - for line in osRelease: - if line.startswith("NAME="): - line = line.lower() - if "fedora" in line: - detectOS.result = "Fedora" - elif "opensuse" in line: - detectOS.result = "openSUSE" - elif "ubuntu" in line: - detectOS.result = "Ubuntu" - elif "debian" in line: - detectOS.result = "Debian" - elif "gentoo" in line or "calculate" in line: - detectOS.result = "Gentoo" - else: - detectOS.result = None - if line.startswith("VERSION_ID="): - try: - version = float(line.split("=")[1].replace("\"", "")) - except ValueError: - pass - if detectOS.result == "Ubuntu" and version < 14: - detectOS.result = "Ubuntu 12" +# OS-specific dependencies for optional components listed in EXTRAS_REQUIRE +EXTRAS_REQUIRE_DEPS = { + # The values from setup.EXTRAS_REQUIRE + 'python_prctl': { + # The packages needed for this requirement, by OS + "OpenBSD": [""], + "FreeBSD": [""], + "Debian": ["libcap-dev python-prctl"], + "Ubuntu": ["libcap-dev python-prctl"], + "Ubuntu 12": ["libcap-dev python-prctl"], + "openSUSE": [""], + "Fedora": ["prctl"], + "Guix": [""], + "Gentoo": ["dev-python/python-prctl"], + }, +} -def detectOS(): - if detectOS.result is not None: - return detectOS.result - if sys.platform.startswith('openbsd'): - detectOS.result = "OpenBSD" - elif sys.platform.startswith('freebsd'): - detectOS.result = "FreeBSD" - elif sys.platform.startswith('win'): - detectOS.result = "Windows" - elif os.path.isfile("/etc/os-release"): - detectOSRelease() - elif os.path.isfile("/etc/config.scm"): - detectOS.result = "Guix" - return detectOS.result def detectPrereqs(missing=True): available = [] @@ -176,18 +66,21 @@ def detectPrereqs(missing=True): available.append(module) return available + def prereqToPackages(): if not detectPrereqs(): return - print "%s %s" % ( + print("%s %s" % ( PACKAGE_MANAGER[detectOS()], " ".join( - PACKAGES[x][detectOS()] for x in detectPrereqs())) + PACKAGES[x][detectOS()] for x in detectPrereqs()))) + def compilerToPackages(): if not detectOS() in COMPILING: return - print "%s %s" % ( - PACKAGE_MANAGER[detectOS.result], COMPILING[detectOS.result]) + print("%s %s" % ( + PACKAGE_MANAGER[detectOS.result], COMPILING[detectOS.result])) + def testCompiler(): if not HAVE_SETUPTOOLS: @@ -214,30 +107,30 @@ def testCompiler(): fullPath = os.path.join(cmd.build_lib, cmd.get_ext_filename("bitmsghash")) return os.path.isfile(fullPath) -detectOS.result = None -prereqs = detectPrereqs() +prereqs = detectPrereqs() compiler = testCompiler() if (not compiler or prereqs) and detectOS() in PACKAGE_MANAGER: - print "It looks like you're using %s. " \ - "It is highly recommended to use the package manager\n" \ - "to install the missing dependencies." % (detectOS.result) + print( + "It looks like you're using %s. " + "It is highly recommended to use the package manager\n" + "to install the missing dependencies." % detectOS.result) if not compiler: - print "Building the bitmsghash module failed.\n" \ - "You may be missing a C++ compiler and/or the OpenSSL headers." + print( + "Building the bitmsghash module failed.\n" + "You may be missing a C++ compiler and/or the OpenSSL headers.") if prereqs: - mandatory = list(x for x in prereqs if "optional" not in PACKAGES[x] or not PACKAGES[x]["optional"]) - optional = list(x for x in prereqs if "optional" in PACKAGES[x] and PACKAGES[x]["optional"]) - + mandatory = [x for x in prereqs if not PACKAGES[x].get("optional")] + optional = [x for x in prereqs if PACKAGES[x].get("optional")] if mandatory: - print "Missing mandatory dependencies: %s" % (" ".join(mandatory)) + print("Missing mandatory dependencies: %s" % " ".join(mandatory)) if optional: - print "Missing optional dependencies: %s" % (" ".join(optional)) + print("Missing optional dependencies: %s" % " ".join(optional)) for package in optional: - print PACKAGES[package].get('description') + print(PACKAGES[package].get('description')) # Install the system dependencies of optional extras_require components OPSYS = detectOS() @@ -259,12 +152,14 @@ for lhs, rhs in EXTRAS_REQUIRE.items(): if x in EXTRAS_REQUIRE_DEPS ]), ]) - print "Optional dependency `pip install .[{}]` would require `{}` to be run as root".format(lhs, rhs_cmd) + print( + "Optional dependency `pip install .[{}]` would require `{}`" + " to be run as root".format(lhs, rhs_cmd)) -if (not compiler or prereqs) and detectOS() in PACKAGE_MANAGER: - print "You can install the missing dependencies by running, as root:" +if (not compiler or prereqs) and OPSYS in PACKAGE_MANAGER: + print("You can install the missing dependencies by running, as root:") if not compiler: compilerToPackages() prereqToPackages() else: - print "All the dependencies satisfied, you can install PyBitmessage" + print("All the dependencies satisfied, you can install PyBitmessage") diff --git a/src/depends.py b/src/depends.py index 62d92228..66ed0a16 100755 --- a/src/depends.py +++ b/src/depends.py @@ -1,8 +1,8 @@ -#!/usr/bin/env python2 +""" +Utility functions to check the availability of dependencies +and suggest how it may be installed +""" -import os -import pyelliptic.openssl -import subprocess import sys # Only really old versions of Python don't have sys.hexversion. We don't @@ -14,22 +14,160 @@ if not hasattr(sys, 'hexversion') or sys.hexversion < 0x20300F0: % sys.version ) -# We can now use logging so set up a simple configuration import logging +import os +from importlib import import_module + +# We can now use logging so set up a simple configuration formatter = logging.Formatter( '%(levelname)s: %(message)s' ) handler = logging.StreamHandler(sys.stdout) handler.setFormatter(formatter) -logger = logging.getLogger(__name__) +logger = logging.getLogger('both') logger.addHandler(handler) logger.setLevel(logging.ERROR) +PACKAGE_MANAGER = { + "OpenBSD": "pkg_add", + "FreeBSD": "pkg install", + "Debian": "apt-get install", + "Ubuntu": "apt-get install", + "Ubuntu 12": "apt-get install", + "openSUSE": "zypper install", + "Fedora": "dnf install", + "Guix": "guix package -i", + "Gentoo": "emerge" +} + +PACKAGES = { + "PyQt4": { + "OpenBSD": "py-qt4", + "FreeBSD": "py27-qt4", + "Debian": "python-qt4", + "Ubuntu": "python-qt4", + "Ubuntu 12": "python-qt4", + "openSUSE": "python-qt", + "Fedora": "PyQt4", + "Guix": "python2-pyqt@4.11.4", + "Gentoo": "dev-python/PyQt4", + "optional": True, + "description": + "You only need PyQt if you want to use the GUI." + " When only running as a daemon, this can be skipped.\n" + "However, you would have to install it manually" + " because setuptools does not support PyQt." + }, + "msgpack": { + "OpenBSD": "py-msgpack", + "FreeBSD": "py27-msgpack-python", + "Debian": "python-msgpack", + "Ubuntu": "python-msgpack", + "Ubuntu 12": "msgpack-python", + "openSUSE": "python-msgpack-python", + "Fedora": "python2-msgpack", + "Guix": "python2-msgpack", + "Gentoo": "dev-python/msgpack", + "optional": True, + "description": + "python-msgpack is recommended for improved performance of" + " message encoding/decoding" + }, + "pyopencl": { + "FreeBSD": "py27-pyopencl", + "Debian": "python-pyopencl", + "Ubuntu": "python-pyopencl", + "Ubuntu 12": "python-pyopencl", + "Fedora": "python2-pyopencl", + "openSUSE": "", + "OpenBSD": "", + "Guix": "", + "Gentoo": "dev-python/pyopencl", + "optional": True, + "description": + "If you install pyopencl, you will be able to use" + " GPU acceleration for proof of work.\n" + "You also need a compatible GPU and drivers." + }, + "setuptools": { + "OpenBSD": "py-setuptools", + "FreeBSD": "py27-setuptools", + "Debian": "python-setuptools", + "Ubuntu": "python-setuptools", + "Ubuntu 12": "python-setuptools", + "Fedora": "python2-setuptools", + "openSUSE": "python-setuptools", + "Guix": "python2-setuptools", + "Gentoo": "dev-python/setuptools", + "optional": False, + } +} + + +def detectOS(): + if detectOS.result is not None: + return detectOS.result + if sys.platform.startswith('openbsd'): + detectOS.result = "OpenBSD" + elif sys.platform.startswith('freebsd'): + detectOS.result = "FreeBSD" + elif sys.platform.startswith('win'): + detectOS.result = "Windows" + elif os.path.isfile("/etc/os-release"): + detectOSRelease() + elif os.path.isfile("/etc/config.scm"): + detectOS.result = "Guix" + return detectOS.result + + +detectOS.result = None + + +def detectOSRelease(): + with open("/etc/os-release", 'r') as osRelease: + version = None + for line in osRelease: + if line.startswith("NAME="): + line = line.lower() + if "fedora" in line: + detectOS.result = "Fedora" + elif "opensuse" in line: + detectOS.result = "openSUSE" + elif "ubuntu" in line: + detectOS.result = "Ubuntu" + elif "debian" in line: + detectOS.result = "Debian" + elif "gentoo" in line or "calculate" in line: + detectOS.result = "Gentoo" + else: + detectOS.result = None + if line.startswith("VERSION_ID="): + try: + version = float(line.split("=")[1].replace("\"", "")) + except ValueError: + pass + if detectOS.result == "Ubuntu" and version < 14: + detectOS.result = "Ubuntu 12" + + +def try_import(module, log_extra=False): + try: + return import_module(module) + except ImportError: + module = module.split('.')[0] + logger.error('The %s module is not available.', module) + if log_extra: + logger.error(log_extra) + dist = detectOS() + logger.error( + 'On %s, try running "%s %s" as root.', + dist, PACKAGE_MANAGER[dist], PACKAGES[module][dist]) + return False + + # We need to check hashlib for RIPEMD-160, as it won't be available # if OpenSSL is not linked against or the linked OpenSSL has RIPEMD # disabled. - - def check_hashlib(): """Do hashlib check. @@ -73,19 +211,18 @@ def check_sqlite(): logger.error( 'On FreeBSD, try running "pkg install py27-sqlite3" as root.') return False - try: - import sqlite3 - except ImportError: - logger.error('The sqlite3 module is not available') + + sqlite3 = try_import('sqlite3') + if not sqlite3: return False logger.info('sqlite3 Module Version: %s', sqlite3.version) logger.info('SQLite Library Version: %s', sqlite3.sqlite_version) # sqlite_version_number formula: https://sqlite.org/c3ref/c_source_id.html sqlite_version_number = ( - sqlite3.sqlite_version_info[0] * 1000000 - + sqlite3.sqlite_version_info[1] * 1000 - + sqlite3.sqlite_version_info[2] + sqlite3.sqlite_version_info[0] * 1000000 + + sqlite3.sqlite_version_info[1] * 1000 + + sqlite3.sqlite_version_info[2] ) conn = None @@ -126,11 +263,10 @@ def check_openssl(): Here we are checking for openssl with its all dependent libraries and version checking. """ - try: - import ctypes - except ImportError: - logger.error( - 'Unable to check OpenSSL. The ctypes module is not available.') + + ctypes = try_import('ctypes') + if not ctypes: + logger.error('Unable to check OpenSSL.') return False # We need to emulate the way PyElliptic searches for OpenSSL. @@ -163,6 +299,8 @@ def check_openssl(): cflags_regex = re.compile(r'(?:OPENSSL_NO_)(AES|EC|ECDH|ECDSA)(?!\w)') + import pyelliptic.openssl + for path in paths: logger.info('Checking OpenSSL at %s', path) try: @@ -213,21 +351,20 @@ def check_curses(): 'The curses interface requires the pythondialog package and' ' the dialog utility.') return False - try: - import curses - except ImportError: - logger.error( - 'The curses interface can not be used. The curses module' - ' is not available.') + curses = try_import('curses') + if not curses: + logger.error('The curses interface can not be used.') return False + logger.info('curses Module Version: %s', curses.version) - try: - import dialog - except ImportError: - logger.error( - 'The curses interface can not be used. The pythondialog' - ' package is not available.') + + dialog = try_import('dialog') + if not dialog: + logger.error('The curses interface can not be used.') return False + + import subprocess + try: subprocess.check_call('which dialog') except subprocess.CalledProcessError: @@ -249,54 +386,23 @@ def check_pyqt(): """Do pyqt dependency check. Here we are checking for PyQt4 with its version, as for it require - PyQt 4.7 or later. + PyQt 4.8 or later. """ - try: - import PyQt4.QtCore - except ImportError: - logger.error( - 'The PyQt4 package is not available. PyBitmessage requires' - ' PyQt 4.8 or later and Qt 4.7 or later.') - if sys.platform.startswith('openbsd'): - logger.error('On OpenBSD, try running "pkg_add py-qt4" as root.') - elif sys.platform.startswith('freebsd'): - logger.error( - 'On FreeBSD, try running "pkg install py27-qt4" as root.') - elif os.path.isfile("/etc/os-release"): - with open("/etc/os-release", 'rt') as osRelease: - for line in osRelease: - if line.startswith("NAME="): - if "fedora" in line.lower(): - logger.error( - 'On Fedora, try running' - ' "dnf install PyQt4" as root.') - elif "opensuse" in line.lower(): - logger.error( - 'On openSUSE, try running' - ' "zypper install python-qt" as root.') - elif "ubuntu" in line.lower(): - logger.error( - 'On Ubuntu, try running' - ' "apt-get install python-qt4" as root.') - elif "debian" in line.lower(): - logger.error( - 'On Debian, try running' - ' "apt-get install python-qt4" as root.') - else: - logger.error( - 'If your package manager does not have' - ' this package, try running' - ' "pip install PyQt4".') + QtCore = try_import( + 'PyQt4.QtCore', 'PyBitmessage requires PyQt 4.8 or later and Qt 4.7 or later.') + + if not QtCore: return False - logger.info('PyQt Version: %s', PyQt4.QtCore.PYQT_VERSION_STR) - logger.info('Qt Version: %s', PyQt4.QtCore.QT_VERSION_STR) + + logger.info('PyQt Version: %s', QtCore.PYQT_VERSION_STR) + logger.info('Qt Version: %s', QtCore.QT_VERSION_STR) passed = True - if PyQt4.QtCore.PYQT_VERSION < 0x40800: + if QtCore.PYQT_VERSION < 0x40800: logger.error( 'This version of PyQt is too old. PyBitmessage requries' ' PyQt 4.8 or later.') passed = False - if PyQt4.QtCore.QT_VERSION < 0x40700: + if QtCore.QT_VERSION < 0x40700: logger.error( 'This version of Qt is too old. PyBitmessage requries' ' Qt 4.7 or later.') @@ -310,47 +416,8 @@ def check_msgpack(): simply checking if msgpack package with all its dependency is available or not as recommended for messages coding. """ - try: - import msgpack - except ImportError: - logger.error( - 'The msgpack package is not available.' - 'It is highly recommended for messages coding.') - if sys.platform.startswith('openbsd'): - logger.error( - 'On OpenBSD, try running "pkg_add py-msgpack" as root.') - elif sys.platform.startswith('freebsd'): - logger.error( - 'On FreeBSD, try running "pkg install py27-msgpack-python"' - ' as root.') - elif os.path.isfile("/etc/os-release"): - with open("/etc/os-release", 'rt') as osRelease: - for line in osRelease: - if line.startswith("NAME="): - if "fedora" in line.lower(): - logger.error( - 'On Fedora, try running' - ' "dnf install python2-msgpack" as root.') - elif "opensuse" in line.lower(): - logger.error( - 'On openSUSE, try running' - ' "zypper install python-msgpack-python"' - ' as root.') - elif "ubuntu" in line.lower(): - logger.error( - 'On Ubuntu, try running' - ' "apt-get install python-msgpack" as root.') - elif "debian" in line.lower(): - logger.error( - 'On Debian, try running' - ' "apt-get install python-msgpack" as root.') - else: - logger.error( - 'If your package manager does not have' - ' this package, try running' - ' "pip install msgpack-python".') - - return True + return try_import( + 'msgpack', 'It is highly recommended for messages coding.') is not False def check_dependencies(verbose=False, optional=False): @@ -381,10 +448,9 @@ def check_dependencies(verbose=False, optional=False): ' or greater is required.') has_all_dependencies = False - check_functions = [ - check_hashlib, check_sqlite, check_openssl, check_msgpack] + check_functions = [check_hashlib, check_sqlite, check_openssl] if optional: - check_functions.extend([check_pyqt, check_curses]) + check_functions.extend([check_msgpack, check_pyqt, check_curses]) # Unexpected exceptions are handled here for check in check_functions: @@ -399,8 +465,3 @@ def check_dependencies(verbose=False, optional=False): 'PyBitmessage cannot start. One or more dependencies are' ' unavailable.' ) - - -if __name__ == '__main__': - """Check Dependencies""" - check_dependencies(True, True)