Skip to content

Commit

Permalink
feat: allow custom plugin specification in Docker file and other Dock…
Browse files Browse the repository at this point in the history
…er / plugin improvements (#1029)
  • Loading branch information
antazoey committed Sep 15, 2022
1 parent d496cee commit b3dc493
Show file tree
Hide file tree
Showing 13 changed files with 272 additions and 142 deletions.
44 changes: 36 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
FROM ubuntu:22.04
RUN apt-get update && apt-get upgrade --yes && apt-get install git python3.9 python3-pip --yes
ADD . /code
WORKDIR /code

RUN pip install .
RUN ape plugins install alchemy ens etherscan foundry hardhat infura ledger solidity template tokens trezor vyper
RUN pip install eth-rlp==0.3.0
#---------------------------------------------------------------------------------------------
# See LICENSE in the project root for license information.
#---------------------------------------------------------------------------------------------

ARG PYTHON_VERSION="3.9"
ARG PLUGINS_FILE="./recommended-plugins.txt"

FROM python:${PYTHON_VERSION}

RUN apt-get update && apt-get upgrade --yes && apt-get install git

# See http://label-schema.org for metadata schema
# TODO: Add `build-date` and `version`
LABEL maintainer="ApeWorX" \
org.label-schema.schema-version="2.0" \
org.label-schema.name="ape" \
org.label-schema.description="Ape Ethereum Framework." \
org.label-schema.url="https://docs.apeworx.io/ape/stable/" \
org.label-schema.usage="https://docs.apeworx.io/ape/stable/userguides/quickstart.html#via-docker" \
org.label-schema.vcs-url="https://github.com/ApeWorX/ape" \
org.label-schema.docker.cmd="docker run --volume $HOME/.ape:/root/.ape --volume $HOME/.vvm:/root/.vvm --volume $HOME/.solcx:/root/.solcx --volume $PWD:/root/project --workdir /root/project apeworx/ape compile"

RUN useradd --create-home --shell /bin/bash harambe
WORKDIR /home/harambe
COPY . .

RUN pip install --upgrade pip \
&& pip install --no-cache-dir . \
&& pip install -r recommended-plugins.txt \
# Fix RLP installation issue
&& pip uninstall rlp --yes \
&& pip install rlp==3.0.0 \
# Validate installation
&& ape --version

USER harambe
ENTRYPOINT ["ape"]
12 changes: 12 additions & 0 deletions recommended-plugins.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ape-alchemy
ape-ens
ape-etherscan
ape-foundry
ape-hardhat
ape-infura
ape-ledger
ape-solidity
ape-template
ape-tokens
ape-trezor
ape-vyper
17 changes: 2 additions & 15 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"hypothesis-jsonschema==0.19.0", # JSON Schema fuzzer extension
],
"lint": [
"black>=22.3.0,<23.0", # auto-formatter and linter
"black>=22.6.0,<23.0", # auto-formatter and linter
"mypy>=0.971,<1.0", # Static type analyzer
"types-PyYAML", # NOTE: Needed due to mypy typeshed
"types-requests", # NOTE: Needed due to mypy typeshed
Expand Down Expand Up @@ -52,20 +52,7 @@
# NOTE: These are extras that someone can install to get up and running quickly w/ ape
# They should be kept up to date with what works and what doesn't out of the box
# Usage example: `pipx install eth-ape[recommended-plugins]`
"recommended-plugins": [
"ape-alchemy", # Alchemy public network provider
"ape-ens", # ENS converter
"ape-etherscan", # Etherscan explorer plugin
"ape-foundry", # Foundry local and fork network EVM provider
"ape-hardhat", # Hardhat local and fork network EVM provider
"ape-infura", # Infura public network provider
"ape-ledger", # Ledger Nano S/X hardware wallet
"ape-solidity", # Solidity compiler support
"ape-template", # Cookiecutter template support
"ape-tokens", # Tokenlists converter
"ape-trezor", # Trezor Model T/One hardware wallet
"ape-vyper", # Vyper compiler support
],
"recommended-plugins": (here / "recommended-plugins.txt").read_text().split("\n"),
}

# NOTE: `pip install -e .[dev]` to install package
Expand Down
2 changes: 1 addition & 1 deletion src/ape/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class AllPluginHooks(


def clean_plugin_name(name: str) -> str:
return name.replace("ape_", "").replace("_", "-")
return name.replace("_", "-").replace("ape-", "")


def get_hooks(plugin_type):
Expand Down
61 changes: 32 additions & 29 deletions src/ape_plugins/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from ape.managers.config import CONFIG_FILE_NAME
from ape.plugins import plugin_manager
from ape.utils import add_padding_to_strings, github_client, load_config
from ape_plugins.utils import ApePlugin, ModifyPluginResultHandler
from ape_plugins.utils import ModifyPluginResultHandler, PluginInstallRequest


@click.group(short_help="Manage ape plugins")
Expand Down Expand Up @@ -46,22 +46,24 @@ def callback(ctx, param, value: Tuple[str]):
ctx.obj.abort("You must give at least one requirement to install.")

elif len(value) == 1 and Path(value[0]).resolve().exists():
# User passed in a path to a config file.
config_path = Path(value[0]).expanduser().resolve()
# User passed in a path to a file.
file_path = Path(value[0]).expanduser().resolve()

if config_path.name != CONFIG_FILE_NAME:
config_path = config_path / CONFIG_FILE_NAME
config = load_config(config_path)
# Config file
if file_path.name != CONFIG_FILE_NAME:
file_path = file_path / CONFIG_FILE_NAME

config = load_config(file_path)
plugins = config.get("plugins") or []

if not plugins:
ctx.obj.logger.warning(f"No plugins found in config '{config_path}'.")
ctx.obj.logger.warning(f"No plugins found at '{file_path}'.")
sys.exit(0)

return [ApePlugin.from_dict(d) for d in plugins]
return [PluginInstallRequest.parse_obj(d) for d in plugins]

else:
return [ApePlugin(v) for v in value]
return [PluginInstallRequest(name=v) for v in value]

return click.argument(
"plugins",
Expand Down Expand Up @@ -100,16 +102,16 @@ def _list(cli_ctx, display_all):
spaced_names = add_padding_to_strings([p[0] for p in plugin_list], extra_spaces=4)

for name in spaced_names:
plugin = ApePlugin(name.strip())
if plugin.is_part_of_core:
plugin = PluginInstallRequest(name=name.strip())
if plugin.in_core:
if not display_all:
continue

installed_core_plugins.add(name)

elif plugin.is_available:
installed_org_plugins[name] = plugin.current_version
elif not plugin.is_part_of_core or not plugin.is_available:
elif not plugin.in_core or not plugin.is_available:
installed_third_party_plugins[name] = plugin.current_version
else:
cli_ctx.logger.error(f"'{plugin.name}' is not a plugin.")
Expand Down Expand Up @@ -162,44 +164,44 @@ def install(cli_ctx, plugins, skip_confirmation, upgrade):
"""Install plugins"""

failures_occurred = False
for plugin in plugins:
if plugin.is_part_of_core:
cli_ctx.logger.error(f"Cannot install core 'ape' plugin '{plugin.name}'.")
for plugin_request in plugins:
if plugin_request.in_core:
cli_ctx.logger.error(f"Cannot install core 'ape' plugin '{plugin_request.name}'.")
failures_occurred = True
continue

elif plugin.requested_version is not None and upgrade:
elif plugin_request.version is not None and upgrade:
cli_ctx.logger.error(
f"Cannot use '--upgrade' option when specifying "
f"a version for plugin '{plugin.name}'."
f"a version for plugin '{plugin_request.name}'."
)
failures_occurred = True
continue

# if plugin is installed but not a 2nd class. It must be a third party
elif not plugin.is_installed and not plugin.is_available:
cli_ctx.logger.warning(f"Plugin '{plugin.name}' is not an trusted plugin.")
elif not plugin_request.is_installed and not plugin_request.is_available:
cli_ctx.logger.warning(f"Plugin '{plugin_request.name}' is not an trusted plugin.")

result_handler = ModifyPluginResultHandler(cli_ctx.logger, plugin)
result_handler = ModifyPluginResultHandler(cli_ctx.logger, plugin_request)
args = [sys.executable, "-m", "pip", "install", "--quiet"]

if upgrade:
cli_ctx.logger.info(f"Upgrading '{plugin.name}'...")
args.extend(("--upgrade", plugin.package_name))
cli_ctx.logger.info(f"Upgrading '{plugin_request.name}'...")
args.extend(("--upgrade", plugin_request.package_name))

version_before = plugin.current_version
version_before = plugin_request.current_version
result = subprocess.call(args)

# Returns ``True`` when upgraded successfully
failures_occurred = not result_handler.handle_upgrade_result(result, version_before)

elif plugin.can_install and (
plugin.is_available
elif plugin_request.can_install and (
plugin_request.is_available
or skip_confirmation
or click.confirm(f"Install unknown 3rd party plugin '{plugin.name}'?")
or click.confirm(f"Install unknown 3rd party plugin '{plugin_request.name}'?")
):
cli_ctx.logger.info(f"Installing {plugin}...")
args.append(plugin.install_str)
cli_ctx.logger.info(f"Installing {plugin_request}...")
args.append(plugin_request.install_str)

# NOTE: Be *extremely careful* with this command, as it modifies the user's
# installed packages, to potentially catastrophic results
Expand All @@ -209,7 +211,8 @@ def install(cli_ctx, plugins, skip_confirmation, upgrade):

else:
cli_ctx.logger.warning(
f"'{plugin.name}' is already installed. Did you mean to include '--upgrade'."
f"'{plugin_request.name}' is already installed. "
f"Did you mean to include '--upgrade'."
)

if failures_occurred:
Expand Down

0 comments on commit b3dc493

Please sign in to comment.