From 3a6de359dc31375df46418e6ffd7f45ab9567287 Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Mon, 3 Jul 2017 13:23:37 -0600 Subject: [PATCH] Support for 0.4.12 and installation of solc by version --- .travis.yml | 21 +- pytest.ini | 2 + scripts/install_solc.py | 89 ++-- solc/install.py | 455 +++++++++++++++++++ solc/main.py | 27 +- solc/wrapper.py | 8 +- tests/conftest.py | 2 +- tests/installation/test_solc_installation.py | 66 +++ tox.ini | 6 +- 9 files changed, 626 insertions(+), 50 deletions(-) create mode 100644 pytest.ini create mode 100644 solc/install.py create mode 100644 tests/installation/test_solc_installation.py diff --git a/.travis.yml b/.travis.yml index 86d3978..37ba1e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,19 @@ language: python python: - "3.5" +os: + - linux + #- osx dist: trusty sudo: required env: global: + - SOLC_BASE_INSTALL_PATH=$TRAVIS_BUILD_DIR matrix: + # Installation Tests + - TOX_ENV=py27-installation SOLC_RUN_INSTALL_TESTS=enabled + - TOX_ENV=py34-installation SOLC_RUN_INSTALL_TESTS=enabled + - TOX_ENV=py35-installation SOLC_RUN_INSTALL_TESTS=enabled # Standard Library # py27 - TOX_ENV=py27-stdlib SOLC_VERSION=v0.4.1 @@ -15,6 +23,7 @@ env: - TOX_ENV=py27-stdlib SOLC_VERSION=v0.4.8 - TOX_ENV=py27-stdlib SOLC_VERSION=v0.4.9 - TOX_ENV=py27-stdlib SOLC_VERSION=v0.4.11 + - TOX_ENV=py27-stdlib SOLC_VERSION=v0.4.12 # py34 - TOX_ENV=py34-stdlib SOLC_VERSION=v0.4.1 - TOX_ENV=py34-stdlib SOLC_VERSION=v0.4.2 @@ -23,6 +32,7 @@ env: - TOX_ENV=py34-stdlib SOLC_VERSION=v0.4.8 - TOX_ENV=py34-stdlib SOLC_VERSION=v0.4.9 - TOX_ENV=py34-stdlib SOLC_VERSION=v0.4.11 + - TOX_ENV=py34-stdlib SOLC_VERSION=v0.4.12 # py35 - TOX_ENV=py35-stdlib SOLC_VERSION=v0.4.1 - TOX_ENV=py35-stdlib SOLC_VERSION=v0.4.2 @@ -31,6 +41,7 @@ env: - TOX_ENV=py35-stdlib SOLC_VERSION=v0.4.8 - TOX_ENV=py35-stdlib SOLC_VERSION=v0.4.9 - TOX_ENV=py35-stdlib SOLC_VERSION=v0.4.11 + - TOX_ENV=py35-stdlib SOLC_VERSION=v0.4.12 # Gevent # py27 - TOX_ENV=py27-gevent SOLC_VERSION=v0.4.1 @@ -40,6 +51,7 @@ env: - TOX_ENV=py27-gevent SOLC_VERSION=v0.4.8 - TOX_ENV=py27-gevent SOLC_VERSION=v0.4.9 - TOX_ENV=py27-gevent SOLC_VERSION=v0.4.11 + - TOX_ENV=py27-gevent SOLC_VERSION=v0.4.12 # py34 - TOX_ENV=py34-gevent SOLC_VERSION=v0.4.1 - TOX_ENV=py34-gevent SOLC_VERSION=v0.4.2 @@ -48,6 +60,7 @@ env: - TOX_ENV=py34-gevent SOLC_VERSION=v0.4.8 - TOX_ENV=py34-gevent SOLC_VERSION=v0.4.9 - TOX_ENV=py34-gevent SOLC_VERSION=v0.4.11 + - TOX_ENV=py34-gevent SOLC_VERSION=v0.4.12 # py35 - TOX_ENV=py35-gevent SOLC_VERSION=v0.4.1 - TOX_ENV=py35-gevent SOLC_VERSION=v0.4.2 @@ -56,18 +69,20 @@ env: - TOX_ENV=py35-gevent SOLC_VERSION=v0.4.8 - TOX_ENV=py35-gevent SOLC_VERSION=v0.4.9 - TOX_ENV=py35-gevent SOLC_VERSION=v0.4.11 + - TOX_ENV=py35-gevent SOLC_VERSION=v0.4.12 # linting - TOX_ENV=flake8 cache: - pip: true before_install: install: - - if [ -n "$SOLC_VERSION" ]; then python3 $TRAVIS_BUILD_DIR/scripts/install_solc.py $SOLC_VERSION; fi - travis_retry pip install setuptools --upgrade - travis_retry pip install tox + - pip3 install -e . # install py-solc globally in order to use the solc installation scripts. before_script: - - if [ -n "$SOLC_VERSION" ]; then export SOLC_BINARY="$TRAVIS_BUILD_DIR/bin/solc-$SOLC_VERSION/bin/solc"; fi - - if [ -n "$SOLC_VERSION" ]; then export LD_LIBRARY_PATH="$TRAVIS_BUILD_DIR/bin/solc-$SOLC_VERSION/bin"; fi + - if [ -n "$SOLC_VERSION" ]; then python3 -m solc.install $SOLC_VERSION; fi + - if [ -n "$SOLC_VERSION" ]; then export SOLC_BINARY="$SOLC_BASE_INSTALL_PATH/solc-$SOLC_VERSION/bin/solc"; fi + - if [ -n "$SOLC_VERSION" ]; then export LD_LIBRARY_PATH="$SOLC_BASE_INSTALL_PATH/solc-$SOLC_VERSION/bin"; fi - env - if [ -n "$SOLC_BINARY" ]; then $SOLC_BINARY --version; fi script: diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..beaabb6 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +addopts= -v --showlocals diff --git a/scripts/install_solc.py b/scripts/install_solc.py index 2f2927c..9c8b50f 100644 --- a/scripts/install_solc.py +++ b/scripts/install_solc.py @@ -19,14 +19,19 @@ import zipfile -SUPPORTED_VERSIONS = { - "0.4.1", - "0.4.2", - "0.4.6", - "0.4.7", - "0.4.8", - "0.4.11", -} +V0_4_1 = 'v0.4.1' +V0_4_2 = 'v0.4.2' +V0_4_6 = 'v0.4.6' +V0_4_7 = 'v0.4.7' +V0_4_8 = 'v0.4.8' +V0_4_9 = 'v0.4.9' +V0_4_11 = 'v0.4.11' +V0_4_12 = 'v0.4.12' + + +LINUX = 'linux' +OSX = 'darwin' +WINDOWS = 'win32' BASE_INSTALL_PATH = os.path.join( @@ -41,6 +46,17 @@ ) +def get_platform(): + if sys.platform.startswith('linux'): + return LINUX + elif sys.platform == OSX: + return OSX + elif sys.platform == WINDOWS: + return WINDOWS + else: + raise KeyError("Unknown platform: {0}".format(sys.platform)) + + def is_executable_available(program): def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) @@ -280,26 +296,6 @@ def install_solc_from_static_linux(identifier): print("solc successfully installed at: {0}".format(executable_path)) -V0_4_1 = 'v0.4.1' -V0_4_2 = 'v0.4.2' -V0_4_6 = 'v0.4.6' -V0_4_7 = 'v0.4.7' -V0_4_8 = 'v0.4.8' -V0_4_9 = 'v0.4.9' -V0_4_11 = 'v0.4.11' - - -SUPPORTED_VERSIONS = { - V0_4_1, - V0_4_2, - V0_4_6, - V0_4_7, - V0_4_8, - V0_4_9, - V0_4_11, -} - - def install_from_ubuntu_release(identifier): install_solc_dependencies(identifier) install_solc_from_ubuntu_release_zip(identifier) @@ -318,28 +314,41 @@ def install_from_static_linux(identifier): install_v0_4_11 = functools.partial(install_solc_from_static_linux, V0_4_11) +install_v0_4_12 = functools.partial(install_solc_from_static_linux, V0_4_12) INSTALL_FUNCTIONS = { - V0_4_1: install_v0_4_1, - V0_4_2: install_v0_4_2, - V0_4_6: install_v0_4_6, - V0_4_7: install_v0_4_7, - V0_4_8: install_v0_4_8, - V0_4_9: install_v0_4_9, - V0_4_11: install_v0_4_11, + LINUX: { + V0_4_1: install_v0_4_1, + V0_4_2: install_v0_4_2, + V0_4_6: install_v0_4_6, + V0_4_7: install_v0_4_7, + V0_4_8: install_v0_4_8, + V0_4_9: install_v0_4_9, + V0_4_11: install_v0_4_11, + V0_4_12: install_v0_4_12, + }, } -def install_solc(identifier): - if identifier not in SUPPORTED_VERSIONS: +def install_solc(platform, identifier): + if platform not in INSTALL_FUNCTIONS: + raise ValueError( + "Installation of solidity is not supported on your platform ({0}). " + "Supported platforms are: {1}".format( + platform, + ', '.join(sorted(INSTALL_FUNCTIONS.keys())), + ) + ) + elif identifier not in INSTALL_FUNCTIONS[platform]: raise ValueError( "Installation of solidity=={0} is not supported. Must be one of {1}".format( identifier, - ', '.join(sorted(SUPPORTED_VERSIONS)), + ', '.join(sorted(INSTALL_FUNCTIONS[platform].keys())), ) ) - install_fn = INSTALL_FUNCTIONS[identifier] + + install_fn = INSTALL_FUNCTIONS[platform][identifier] install_fn() @@ -350,4 +359,4 @@ def install_solc(identifier): print("Invocation error. Should be invoked as `./install_solc.py `") sys.exit(1) - install_solc(identifier) + install_solc(sys.platform, identifier) diff --git a/solc/install.py b/solc/install.py new file mode 100644 index 0000000..2729a8c --- /dev/null +++ b/solc/install.py @@ -0,0 +1,455 @@ +""" +Install solc +""" +import functools +import os +import stat +import subprocess +import sys +import contextlib + +import zipfile + + +V0_4_1 = 'v0.4.1' +V0_4_2 = 'v0.4.2' +V0_4_6 = 'v0.4.6' +V0_4_7 = 'v0.4.7' +V0_4_8 = 'v0.4.8' +V0_4_9 = 'v0.4.9' +V0_4_11 = 'v0.4.11' +V0_4_12 = 'v0.4.12' + + +LINUX = 'linux' +OSX = 'darwin' +WINDOWS = 'win32' + + +# +# System utilities. +# +@contextlib.contextmanager +def chdir(path): + original_path = os.getcwd() + try: + os.chdir(path) + yield + finally: + os.chdir(original_path) + + +def get_platform(): + if sys.platform.startswith('linux'): + return LINUX + elif sys.platform == OSX: + return OSX + elif sys.platform == WINDOWS: + return WINDOWS + else: + raise KeyError("Unknown platform: {0}".format(sys.platform)) + + +def is_executable_available(program): + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + fpath = os.path.dirname(program) + if fpath: + if is_exe(program): + return True + else: + for path in os.environ["PATH"].split(os.pathsep): + path = path.strip('"') + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return True + + return False + + +def ensure_path_exists(dir_path): + """ + Make sure that a path exists + """ + if not os.path.exists(dir_path): + os.makedirs(dir_path) + return True + return False + + +def ensure_parent_dir_exists(path): + ensure_path_exists(os.path.dirname(path)) + + +def check_subprocess_call(command, message=None, stderr=subprocess.STDOUT, **proc_kwargs): + if message: + print(message) + print("Executing: {0}".format(" ".join(command))) + + return subprocess.check_call( + command, + stderr=subprocess.STDOUT, + **proc_kwargs + ) + + +def check_subprocess_output(command, message=None, stderr=subprocess.STDOUT, **proc_kwargs): + if message: + print(message) + print("Executing: {0}".format(" ".join(command))) + + return subprocess.check_output( + command, + stderr=subprocess.STDOUT, + **proc_kwargs + ) + + +def chmod_plus_x(executable_path): + current_st = os.stat(executable_path) + os.chmod(executable_path, current_st.st_mode | stat.S_IEXEC) + + +SOLIDITY_GIT_URI = "https://github.com/ethereum/solidity.git" + + +def is_git_repository(path): + git_dir = os.path.join( + path, + '.git', + ) + return os.path.exists(git_dir) + + +# +# Installation filesystem path utilities +# +def get_base_install_path(identifier): + if 'SOLC_BASE_INSTALL_PATH' in os.environ: + return os.path.join( + os.environ['SOLC_BASE_INSTALL_PATH'], + 'solc-{0}'.format(identifier), + ) + else: + return os.path.expanduser(os.path.join( + '~', + '.py-solc', + 'solc-{0}'.format(identifier), + )) + + +def get_repository_path(identifier): + return os.path.join( + get_base_install_path(identifier), + 'source', + ) + + +def get_release_zipfile_path(identifier): + return os.path.join( + get_base_install_path(identifier), + 'release.zip', + ) + + +def get_extract_path(identifier): + return os.path.join( + get_base_install_path(identifier), + 'bin', + ) + + +def get_executable_path(identifier): + extract_path = get_extract_path(identifier) + return os.path.join( + extract_path, + 'solc', + ) + + +def get_build_dir(identifier): + repository_path = get_repository_path(identifier) + return os.path.join( + repository_path, + 'build', + ) + + +def get_built_executable_path(identifier): + build_dir = get_build_dir(identifier) + return os.path.join( + build_dir, + 'solc', + 'solc', + ) + + +# +# Installation primitives. +# +def clone_solidity_repository(identifier): + if not is_executable_available('git'): + raise OSError("The `git` is required but was not found") + + repository_path = get_repository_path(identifier) + ensure_parent_dir_exists(repository_path) + command = [ + "git", "clone", + "--recurse-submodules", + "--branch", identifier, + "--depth", "10", + SOLIDITY_GIT_URI, + repository_path, + ] + + return check_subprocess_call( + command, + message="Checking out solidity repository @ {0}".format(identifier), + ) + + +def initialize_repository_submodules(identifier): + if not is_executable_available('git'): + raise OSError("The `git` is required but was not found") + + repository_path = get_repository_path(identifier) + command = [ + "git", "submodule", "update", "--init", "--recursive", + ] + check_subprocess_call( + command, + "Initializing repository submodules @ {0}".format(repository_path), + ) + + +DOWNLOAD_UBUNTU_RELEASE_URI_TEMPLATE = "https://github.com/ethereum/solidity/releases/download/{0}/solidity-ubuntu-trusty.zip" # noqa: E501 + + +def download_ubuntu_release(identifier): + download_uri = DOWNLOAD_UBUNTU_RELEASE_URI_TEMPLATE.format(identifier) + release_zipfile_path = get_release_zipfile_path(identifier) + + ensure_parent_dir_exists(release_zipfile_path) + + command = [ + "wget", download_uri, + '-c', # resume previously incomplete download. + '-O', release_zipfile_path, + ] + + return check_subprocess_call( + command, + message="Downloading ubuntu release from {0}".format(download_uri), + ) + + +DOWNLOAD_STATIC_RELEASE_URI_TEMPLATE = "https://github.com/ethereum/solidity/releases/download/{0}/solc-static-linux" # noqa: E501 + + +def download_static_release(identifier): + download_uri = DOWNLOAD_STATIC_RELEASE_URI_TEMPLATE.format(identifier) + static_binary_path = get_executable_path(identifier) + + ensure_parent_dir_exists(static_binary_path) + + command = [ + "wget", download_uri, + '-c', # resume previously incomplete download. + '-O', static_binary_path, + ] + + return check_subprocess_call( + command, + message="Downloading static linux binary from {0}".format(download_uri), + ) + + +def extract_release(identifier): + release_zipfile_path = get_release_zipfile_path(identifier) + + extract_path = get_extract_path(identifier) + ensure_path_exists(extract_path) + + print("Extracting zipfile: {0} -> {1}".format(release_zipfile_path, extract_path)) + + with zipfile.ZipFile(release_zipfile_path) as zipfile_file: + zipfile_file.extractall(extract_path) + + executable_path = get_executable_path(identifier) + + print("Making `solc` binary executable: `chmod +x {0}`".format(executable_path)) + chmod_plus_x(executable_path) + + +def install_solc_dependencies(identifier): + repository_path = get_repository_path(identifier) + if not is_git_repository(repository_path): + raise OSError("Git repository not found @ {0}".format(repository_path)) + + with chdir(repository_path): + install_deps_script_path = os.path.join(repository_path, 'scripts', 'install_deps.sh') + + return check_subprocess_call( + command=["sh", install_deps_script_path], + message="Running dependency installation script `install_deps.sh` @ {0}".format( + install_deps_script_path, + ), + ) + + +def install_solc_from_ubuntu_release_zip(identifier): + download_ubuntu_release(identifier) + extract_release(identifier) + + extract_path = get_extract_path(identifier) + executable_path = get_executable_path(identifier) + assert os.path.exists(executable_path), "Executable not found @".format(executable_path) + + check_version_command = [executable_path, '--version'] + + check_subprocess_output( + check_version_command, + message="Checking installed executable version @ {0}".format(executable_path), + env={'LD_LIBRARY_PATH': extract_path}, + ) + + print("solc successfully installed at: {0}".format(executable_path)) + + +def install_solc_from_static_linux(identifier): + download_static_release(identifier) + + executable_path = get_executable_path(identifier) + chmod_plus_x(executable_path) + + check_version_command = [executable_path, '--version'] + + check_subprocess_output( + check_version_command, + message="Checking installed executable version @ {0}".format(executable_path), + ) + + print("solc successfully installed at: {0}".format(executable_path)) + + +def build_solc_from_source(identifier): + if not is_git_repository(get_repository_path(identifier)): + clone_solidity_repository(identifier) + + build_dir = get_build_dir(identifier) + ensure_path_exists(build_dir) + + with chdir(build_dir): + cmake_command = ["cmake", ".."] + check_subprocess_call( + cmake_command, + message="Running cmake build command", + ) + make_command = ["make"] + check_subprocess_call( + make_command, + message="Running make command", + ) + + built_executable_path = get_built_executable_path(identifier) + chmod_plus_x(built_executable_path) + + executable_path = get_executable_path(identifier) + ensure_parent_dir_exists(executable_path) + os.symlink(built_executable_path, executable_path) + chmod_plus_x(executable_path) + + +def install_from_ubuntu_release(identifier): + if not is_git_repository(get_repository_path(identifier)): + clone_solidity_repository(identifier) + install_solc_dependencies(identifier) + install_solc_from_ubuntu_release_zip(identifier) + + executable_path = get_executable_path(identifier) + print("Succesfully installed solc @ `{0}`".format(executable_path)) + + +install_v0_4_1_linux = functools.partial(install_from_ubuntu_release, V0_4_1) +install_v0_4_2_linux = functools.partial(install_from_ubuntu_release, V0_4_2) +install_v0_4_6_linux = functools.partial(install_from_ubuntu_release, V0_4_6) +install_v0_4_7_linux = functools.partial(install_from_ubuntu_release, V0_4_7) +install_v0_4_8_linux = functools.partial(install_from_ubuntu_release, V0_4_8) +install_v0_4_9_linux = functools.partial(install_from_ubuntu_release, V0_4_9) + + +def install_from_static_linux(identifier): + install_solc_from_static_linux(identifier) + + executable_path = get_executable_path(identifier) + print("Succesfully installed solc @ `{0}`".format(executable_path)) + + +install_v0_4_11_linux = functools.partial(install_solc_from_static_linux, V0_4_11) +install_v0_4_12_linux = functools.partial(install_solc_from_static_linux, V0_4_12) + + +def install_from_source(identifier): + if not is_git_repository(get_repository_path(identifier)): + clone_solidity_repository(identifier) + install_solc_dependencies(identifier) + build_solc_from_source(identifier) + + executable_path = get_executable_path(identifier) + print("Succesfully installed solc @ `{0}`".format(executable_path)) + + +install_v0_4_8_osx = functools.partial(install_from_source, V0_4_8) +install_v0_4_11_osx = functools.partial(install_from_source, V0_4_11) +install_v0_4_12_osx = functools.partial(install_from_source, V0_4_12) + + +INSTALL_FUNCTIONS = { + LINUX: { + V0_4_1: install_v0_4_1_linux, + V0_4_2: install_v0_4_2_linux, + V0_4_6: install_v0_4_6_linux, + V0_4_7: install_v0_4_7_linux, + V0_4_8: install_v0_4_8_linux, + V0_4_9: install_v0_4_9_linux, + V0_4_11: install_v0_4_11_linux, + V0_4_12: install_v0_4_12_linux, + }, + OSX: { + V0_4_8: install_v0_4_8_osx, + V0_4_11: install_v0_4_11_osx, + V0_4_12: install_v0_4_12_osx, + } +} + + +def install_solc(platform, identifier): + if platform not in INSTALL_FUNCTIONS: + raise ValueError( + "Installation of solidity is not supported on your platform ({0}). " + "Supported platforms are: {1}".format( + platform, + ', '.join(sorted(INSTALL_FUNCTIONS.keys())), + ) + ) + elif identifier not in INSTALL_FUNCTIONS[platform]: + raise ValueError( + "Installation of solidity=={0} is not supported. Must be one of {1}".format( + identifier, + ', '.join(sorted(INSTALL_FUNCTIONS[platform].keys())), + ) + ) + + install_fn = INSTALL_FUNCTIONS[platform][identifier] + install_fn() + + +if __name__ == "__main__": + try: + identifier = sys.argv[1] + except IndexError: + print("Invocation error. Should be invoked as `./install_solc.py `") + sys.exit(1) + + install_solc(sys.platform, identifier) diff --git a/solc/main.py b/solc/main.py index e4ae298..4e04afb 100644 --- a/solc/main.py +++ b/solc/main.py @@ -13,7 +13,7 @@ is_executable_available, ) from .wrapper import ( - SOLC_BINARY, + get_solc_binary_path, solc_wrapper, ) @@ -23,7 +23,11 @@ VERSION_DEV_DATE_MANGLER_RE = re.compile(r'(\d{4})\.0?(\d{1,2})\.0?(\d{1,2})') strip_zeroes_from_month_and_day = functools.partial(VERSION_DEV_DATE_MANGLER_RE.sub, r'\g<1>.\g<2>.\g<3>') -is_solc_available = functools.partial(is_executable_available, SOLC_BINARY) + + +def is_solc_available(): + solc_binary = get_solc_binary_path() + return is_executable_available(solc_binary) def get_solc_version_string(**kwargs): @@ -162,7 +166,24 @@ def compile_standard(input_data, allow_empty=False, **kwargs): **kwargs ) - return json.loads(stdoutdata) + compiler_output = json.loads(stdoutdata) + if 'errors' in compiler_output: + has_errors = any(error['severity'] == 'error' for error in compiler_output['errors']) + if has_errors: + error_message = "\n".join(tuple( + error['formattedMessage'] + for error in compiler_output['errors'] + if error['severity'] == 'error' + )) + raise SolcError( + command, + proc.returncode, + json.dumps(input_data), + stdoutdata, + stderrdata, + message=error_message, + ) + return compiler_output def link_code(unlinked_data, libraries): diff --git a/solc/wrapper.py b/solc/wrapper.py index 0507c98..3ea461c 100644 --- a/solc/wrapper.py +++ b/solc/wrapper.py @@ -12,11 +12,12 @@ ) -SOLC_BINARY = os.environ.get('SOLC_BINARY', 'solc') +def get_solc_binary_path(): + return os.environ.get('SOLC_BINARY', 'solc') @coerce_return_to_text -def solc_wrapper(solc_binary=SOLC_BINARY, +def solc_wrapper(solc_binary=None, stdin=None, help=None, version=None, @@ -48,6 +49,9 @@ def solc_wrapper(solc_binary=SOLC_BINARY, allow_paths=None, standard_json=None, success_return_code=0): + if solc_binary is None: + solc_binary = get_solc_binary_path() + command = [solc_binary] if help: diff --git a/tests/conftest.py b/tests/conftest.py index 01087f2..0d1a62d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,7 +16,7 @@ def contracts_dir(tmpdir): @pytest.fixture() def supported_solc_version(): solc_version = get_solc_version() - if solc_version not in Spec('>=0.4.1,<=0.4.11'): + if solc_version not in Spec('>=0.4.1,<=0.4.12,!=0.4.10,!=0.4.3,!=0.4.4,!=0.4.5'): raise AssertionError("Unsupported compiler version: {0}".format(solc_version)) return solc_version diff --git a/tests/installation/test_solc_installation.py b/tests/installation/test_solc_installation.py new file mode 100644 index 0000000..10161bf --- /dev/null +++ b/tests/installation/test_solc_installation.py @@ -0,0 +1,66 @@ +import os + +import pytest + +import semantic_version + +from solc import ( + get_solc_version, +) +from solc.install import ( + INSTALL_FUNCTIONS, + get_platform, + install_solc, + get_executable_path, + get_extract_path, +) + + +INSTALLATION_TEST_PARAMS = tuple( + (platform, version) + for platform, platform_install_functions in INSTALL_FUNCTIONS.items() + for version in platform_install_functions.keys() +) + + +@pytest.mark.skipif( + 'SOLC_RUN_INSTALL_TESTS' not in os.environ, + reason=( + "Installation tests will not run unless `SOLC_RUN_INSTALL_TESTS` " + "environment variable is set" + ), +) +@pytest.mark.parametrize( + "platform,version", + INSTALLATION_TEST_PARAMS, +) +def test_solc_installation_as_function_call(monkeypatch, tmpdir, platform, version): + if get_platform() != platform: + pytest.skip("Wront platform for install script") + + base_install_path = str(tmpdir.mkdir("temporary-dir")) + monkeypatch.setenv('SOLC_BASE_INSTALL_PATH', base_install_path) + + # sanity check that it's not already installed. + executable_path = get_executable_path(version) + assert not os.path.exists(executable_path) + + install_solc(platform, version) + + assert os.path.exists(executable_path) + monkeypatch.setenv('SOLC_BINARY', executable_path) + + extract_path = get_extract_path(version) + if os.path.exists(extract_path): + contains_so_file = any( + os.path.basename(path).partition(os.path.extsep)[2] == 'so' + for path + in os.listdir(extract_path) + ) + if contains_so_file: + monkeypatch.setenv('LD_LIBRARY_PATH', extract_path) + + actual_version = get_solc_version() + expected_version = semantic_version.Spec(version.lstrip('v')) + + assert actual_version in expected_version diff --git a/tox.ini b/tox.ini index 60ea178..7b9bd91 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,7 @@ [tox] envlist= py{27,34,35}-{gevent,stdlib}, + py{27,34,35}-installation flake8 [flake8] @@ -8,12 +9,15 @@ max-line-length= 100 exclude= tests/* [testenv] -commands=py.test {posargs:tests} +commands= + {gevent,stdlib}: py.test {posargs:tests} + py{27,34,35}-installation: py.test {posargs:-s tests/installation} passenv = SOLC_BINARY TRAVIS_BUILD_DIR setenv = gevent: SOLC_THREADING_BACKEND=gevent + py{27,34,35}-installation: SOLC_RUN_INSTALL_TESTS=enabled deps = -r{toxinidir}/requirements-dev.txt gevent: gevent>=1.1.1,<1.2.0