|
|
|
@ -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)
|
|
|
|
|