diff --git a/Dockerfile b/Dockerfile index 8b310580..45919def 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,4 @@ +# syntax=docker/dockerfile:1.7-labs # Start from a base image with Miniconda installed FROM continuumio/miniconda3 @@ -9,14 +10,36 @@ RUN apt-get update && \ # Set the working directory in the container WORKDIR /backend-api -# Copy the current directory contents and the Conda environment file into the container -COPY . . - # Create the environment from the environment.yml file +COPY environment.yml ./ RUN conda env create -f environment.yml # Make RUN commands use the new environment SHELL ["conda", "run", "-n", "backend-api", "/bin/bash", "-c"] +# Copy Optional wheels directory and handle wheel installation (for utilizing local hummingbot version) +COPY --parents wheels* . + +# Optionally install local Hummingbot wheel if present - use the latest wheel only +RUN if [ -n "$(find wheels/ -name 'hummingbot-*.whl' 2>/dev/null)" ]; then \ + echo "Installing local Hummingbot wheel..." && \ + LATEST_WHEEL=$(find wheels/ -name 'hummingbot-*.whl' | sort -r | head -n1) && \ + echo "Using wheel: $LATEST_WHEEL" && \ + pip install --force-reinstall $LATEST_WHEEL && \ + echo "Local Hummingbot wheel installed successfully"; \ + else \ + echo "No local Hummingbot wheel found, using version from environment.yml"; \ + fi + +# Copy the current directory contents and the Conda environment file into the container +COPY main.py models.py config.py LICENSE README.md ./ +COPY utils/ utils/ +COPY routers/ routers/ +COPY services/ services/ + +COPY bots/controllers bots/credentials bots/scripts bots/__init__.py bots/ + +# Add any other specific directories or files needed + # The code to run when container is started ENTRYPOINT ["conda", "run", "--no-capture-output", "-n", "backend-api", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/Makefile b/Makefile index b608e236..c50e92df 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ .PHONY: install-pre-commit .PHONY: docker_build .PHONY: docker_run +.PHONY: reference-local-hummingbot detect_conda_bin := $(shell bash -c 'if [ "${CONDA_EXE} " == " " ]; then \ @@ -44,7 +45,11 @@ install-pre-commit: fi && pre-commit install' docker_build: - docker build -t hummingbot/backend-api:latest . + docker build -t hummingbot/backend-api$(TAG) . docker_run: docker compose up -d + +# See reference_local_hummingbot.sh for available options +reference-local-hummingbot: + bash ./scripts/reference_local_hummingbot.sh $(if $(force-repackage),--force-repackage,) $(if $(build-env),--build-env=$(build-env),) $(ARGS) \ No newline at end of file diff --git a/scripts/reference_local_hummingbot.sh b/scripts/reference_local_hummingbot.sh new file mode 100755 index 00000000..9fd35038 --- /dev/null +++ b/scripts/reference_local_hummingbot.sh @@ -0,0 +1,166 @@ +#!/bin/bash + +# Script to build, copy and install a Python wheel package from a source directory to a destination directory + +print_usage() { + echo "Usage: $0 [OPTIONS]" + echo "Options:" + echo " --force-repackage Force rebuilding the wheel package" + echo " --source-dir=DIR Source directory containing the Python package (default: ../hummingbot)" + echo " --dest-dir=DIR Destination directory for the wheel file (default: ./wheels)" + echo " --package-name=NAME Name of the package to build (default: hummingbot)" + echo " --conda-env=NAME Conda environment to install into (required if not in environment.yml or .env)" + echo " --build-env=NAME Conda environment to build the package in (default: hummingbot)" + echo " --help Show this help message" + echo "" + echo "When called from Makefile, you can use this format for arguments not in the makefile:" + echo "make reference-local-hummingbot ARGS=\"--force-repackage --source-dir=DIR ...\"" +} + +# Default values +FORCE_REPACKAGE=false +SOURCE_DIR="" +DEST_DIR="" +PACKAGE_NAME="hummingbot" +CONDA_ENV="" +BUILD_ENV="hummingbot" + +# Get current working directory +CWD="$(pwd)" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --force-repackage) + FORCE_REPACKAGE=true + shift + ;; + --source-dir=*) + SOURCE_DIR="${1#*=}" + shift + ;; + --dest-dir=*) + DEST_DIR="${1#*=}" + shift + ;; + --package-name=*) + PACKAGE_NAME="${1#*=}" + shift + ;; + --conda-env=*) + CONDA_ENV="${1#*=}" + shift + ;; + --build-env=*) + BUILD_ENV="${1#*=}" + shift + ;; + --help) + print_usage + exit 0 + ;; + *) + echo "Unknown option: $1" + print_usage + exit 1 + ;; + esac +done + +# Extract conda environment name from environment.yml +if [ -z "$CONDA_ENV" ] && [ -f "$CWD/environment.yml" ]; then + CONDA_ENV=$(grep "^name:" "$CWD/environment.yml" | cut -d ":" -f2 | tr -d " ") +fi + +# If not found in environment.yml, try .env file +if [ -z "$CONDA_ENV" ] && [ -f "$CWD/.env" ]; then + CONDA_ENV=$(grep "^CONDA_ENV=" "$CWD/.env" | cut -d "=" -f2 | tr -d '"' | tr -d "'" | tr -d " ") +fi + +# If still not found, throw an error +if [ -z "$CONDA_ENV" ]; then + echo "Error: Conda environment name not found in environment.yml or .env" + echo "Please specify with --conda-env option or add CONDA_ENV to .env file or name to environment.yml" + exit 1 +fi + +# Set default paths if not provided +if [ -z "$SOURCE_DIR" ]; then + SOURCE_DIR="../$PACKAGE_NAME" +fi + +if [ -z "$DEST_DIR" ]; then + DEST_DIR="./wheels" +fi + +# Convert to absolute paths if relative +if [[ ! "$SOURCE_DIR" = /* ]]; then + SOURCE_DIR="$CWD/$SOURCE_DIR" +fi + +if [[ ! "$DEST_DIR" = /* ]]; then + DEST_DIR="$CWD/$DEST_DIR" +fi + +# Create wheels directory if it doesn't exist +mkdir -p "$DEST_DIR" + +# Check for existing wheel in source directory +cd "$SOURCE_DIR" || { echo "Error: Could not change to source directory: $SOURCE_DIR"; exit 1; } +EXISTING_WHEEL=$(ls "dist/$PACKAGE_NAME-"*.whl 2>/dev/null) +if [ -n "$EXISTING_WHEEL" ] && [ "$FORCE_REPACKAGE" = false ]; then + echo "Found existing wheel: $EXISTING_WHEEL" + WHEEL_FILE="$EXISTING_WHEEL" +else + if [ -n "$EXISTING_WHEEL" ]; then + echo "Force repackage requested, rebuilding wheel..." + rm -f "$EXISTING_WHEEL" + echo "Removed existing wheel: $EXISTING_WHEEL" + fi + + # Build wheel + echo "Building $PACKAGE_NAME wheel in conda environment '$BUILD_ENV'..." + conda run -n $BUILD_ENV python setup.py sdist bdist_wheel + + # Find the wheel file + WHEEL_FILE=$(ls "dist/$PACKAGE_NAME-"*.whl 2>/dev/null) + if [ -z "$WHEEL_FILE" ]; then + echo "Error: No wheel file found in dist directory" + exit 1 + fi +fi + +# Get the wheel filename without path +WHEEL_FILENAME=$(basename "$WHEEL_FILE") + +# Check if there's already a matching wheel file in the destination directory +LOCAL_WHEEL_FILE="$DEST_DIR/$WHEEL_FILENAME" +if [ -f "$LOCAL_WHEEL_FILE" ]; then + # Calculate hashes for both files + SOURCE_HASH=$(sha256sum "$WHEEL_FILE" | cut -d ' ' -f 1) + LOCAL_HASH=$(sha256sum "$LOCAL_WHEEL_FILE" | cut -d ' ' -f 1) + + # Compare hashes + if [ "$SOURCE_HASH" = "$LOCAL_HASH" ]; then + if [ -z "$EXISTING_WHEEL" ] || [ "$FORCE_REPACKAGE" = true ]; then + echo "Existing local $LOCAL_WHEEL_FILE already matches generated $WHEEL_FILE" + else + echo "Existing local $LOCAL_WHEEL_FILE already matches existing $WHEEL_FILE" + fi + echo "Skipping installation as files are identical." + exit 0 + else + echo "Local wheel exists but has different hash, will update..." + fi +fi + +# Copy wheel to destination directory +echo "Copying $(basename "$WHEEL_FILE") to wheels directory..." +cp "$WHEEL_FILE" "$DEST_DIR/" +WHEEL_FILE="$DEST_DIR/$(basename "$WHEEL_FILE")" + +# Install new wheel +echo "Installing $(basename "$WHEEL_FILE") into conda environment '$CONDA_ENV'..." +conda run -n $CONDA_ENV pip install --force-reinstall "$WHEEL_FILE" + +echo -e "\nSuccessfully installed $(basename "$WHEEL_FILE") into conda environment '$CONDA_ENV'"