Skip to content

Commit

Permalink
feat: airplane mode (non-exact compiler version match) [APE-1161] (#114)
Browse files Browse the repository at this point in the history
Co-authored-by: antazoey <admin@antazoey.me>
Co-authored-by: El De-dog-lo <3859395+fubuloubu@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 6, 2023
1 parent 9d6c8f0 commit 7757892
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 6 deletions.
30 changes: 24 additions & 6 deletions ape_solidity/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, Tuple, Type, Union, cast

import solcx # type: ignore
from ape.api import CompilerAPI, PluginConfig
from ape.contracts import ContractInstance
from ape.exceptions import CompilerError, ContractLogicError
Expand All @@ -18,6 +17,11 @@
from requests.exceptions import ConnectionError
from semantic_version import NpmSpec, Version # type: ignore
from solcx import compile_standard # type: ignore
from solcx import ( # type: ignore
get_installable_solc_versions,
get_installed_solc_versions,
install_solc,
)
from solcx.exceptions import SolcError # type: ignore
from solcx.install import get_executable # type: ignore

Expand Down Expand Up @@ -84,15 +88,15 @@ def libraries(self) -> Dict[str, Dict[str, AddressType]]:
def available_versions(self) -> List[Version]:
# NOTE: Package version should already be included in available versions
try:
return solcx.get_installable_solc_versions()
return get_installable_solc_versions()
except ConnectionError:
# Compiling offline
logger.warning("Internet connection required to fetch installable Solidity versions.")
return []

@property
def installed_versions(self) -> List[Version]:
return solcx.get_installed_solc_versions()
return get_installed_solc_versions()

@cached_property
def _ape_version(self) -> Version:
Expand Down Expand Up @@ -557,7 +561,7 @@ def get_version_map(
if self.config.version is not None:
specified_version = Version(self.config.version)
if specified_version not in self.installed_versions:
solcx.install_solc(specified_version)
install_solc(specified_version)

specified_version_with_commit_hash = get_version_with_commit_hash(specified_version)
return {specified_version_with_commit_hash: source_paths_to_get}
Expand All @@ -570,7 +574,7 @@ def get_version_map(
# If no Solidity version has been installed previously while fetching the
# contract version pragma, we must install a compiler, so choose the latest
if not self.installed_versions and not any(source_by_pragma_spec.values()):
solcx.install_solc(max(self.available_versions), show_progress=False)
install_solc(max(self.available_versions), show_progress=False)

# Adjust best-versions based on imports.
files_by_solc_version: Dict[Version, Set[Path]] = {}
Expand Down Expand Up @@ -666,8 +670,22 @@ def _get_pragma_spec(self, path: Path) -> Optional[NpmSpec]:

compiler_version = pragma_spec.select(self.available_versions)
if compiler_version:
solcx.install_solc(compiler_version, show_progress=False)
install_solc(compiler_version, show_progress=False)
else:
# Attempt to use the best-installed version.
for version in self.installed_versions:
if not pragma_spec.match(version):
continue

logger.warning(
"Ape is unable to determine if additional versions are needed "
f"in order to meet spec {pragma_spec}. Resorting to the best matching "
"already-installed version. Alternatively, specify a Solidity "
"compiler version in your ape-config.yaml."
)
return pragma_spec

# None of the installed versions match, and we are unable to install.
raise CompilerError(f"Solidity version specification '{pragma_spec}' could not be met.")

return pragma_spec
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"pytest>=6.0", # Core testing package
"pytest-xdist", # multi-process runner
"pytest-cov", # Coverage analyzer plugin
"pytest-mock", # For creating and using mocks
"hypothesis>=6.2.0,<7.0", # Strategy-based fuzzer
],
"lint": [
Expand Down
13 changes: 13 additions & 0 deletions tests/test_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ape.exceptions import CompilerError
from ethpm_types.ast import ASTClassification
from pkg_resources import get_distribution
from requests.exceptions import ConnectionError
from semantic_version import Version # type: ignore

from ape_solidity import Extension
Expand Down Expand Up @@ -49,6 +50,18 @@ def test_compile(project, contract):
assert contract.source_id == f"{contract.name}.sol"


def test_compile_when_offline(project, compiler, mocker):
# When offline, getting solc versions raises a requests connection error.
# This should trigger the plugin to return an empty list.
patch = mocker.patch("ape_solidity.compiler.get_installable_solc_versions")
patch.side_effect = ConnectionError

# Using a non-specific contract - doesn't matter too much which one.
source_path = project.contracts_folder / "MultipleDefinitions.sol"
result = compiler.compile([source_path])
assert len(result) > 0, "Nothing got compiled."


def test_compile_multiple_definitions_in_source(project, compiler):
source_path = project.contracts_folder / "MultipleDefinitions.sol"
result = compiler.compile([source_path])
Expand Down

0 comments on commit 7757892

Please sign in to comment.