diff --git a/install_offline.sh b/install_offline.sh index 97b0541..d9c387c 100755 --- a/install_offline.sh +++ b/install_offline.sh @@ -1,379 +1,147 @@ -# Makefile for hdwalletpy workflow -# - Build reusable Docker image (Python 3.12) -# - Vendor multi-platform wheels for offline air-gapped use -# - Compile wheels in container (wheelhouse) -# - Create host venv and install from wheelhouse or vendor/ -# - Optionally run inside a warm container +#!/bin/bash +set -e -# ---------- Platform Detection ---------- -UNAME_S := $(shell uname -s) -UNAME_M := $(shell uname -m) +# Parse arguments +DEV_MODE=false +if [ "$1" == "--dev" ]; then + DEV_MODE=true + echo "๐Ÿ› ๏ธ Development mode enabled" +fi -ifeq ($(UNAME_S),Darwin) - PLATFORM := macos - ifeq ($(UNAME_M),arm64) - ARCH := arm64 +# Detect platform +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + PLATFORM="linux-x86_64" +elif [[ "$OSTYPE" == "darwin"* ]]; then + ARCH=$(uname -m) + if [[ "$ARCH" == "arm64" ]]; then + PLATFORM="macos-arm64" else - $(error Unsupported macOS architecture: $(UNAME_M)) - endif -else ifeq ($(UNAME_S),Linux) - PLATFORM := linux - ARCH := x86_64 + echo "ERROR: Only macOS ARM64 is supported" + exit 1 + fi else - $(error Unsupported OS: $(UNAME_S)) -endif + echo "ERROR: Unsupported platform: $OSTYPE" + exit 1 +fi -VENDOR_DIR := vendor/$(PLATFORM)-$(ARCH) +echo "Detected platform: $PLATFORM" -# ---------- Config ---------- -IMAGE := hdwallet-build:3.12 -CONTAINER := hdwallet-dev -WORKDIR := /app -VENV_HOST := .venv -VENV_CONTAINER := /opt/venv -WHEELHOUSE := wheelhouse +# Check if vendor directory exists +VENDOR_PATH="vendor/$PLATFORM" +if [ "$DEV_MODE" = true ]; then + VENDOR_PATH="vendor/$PLATFORM-dev" +fi -# Vendor directories for air-gapped deployment -VENDOR_MACOS := vendor/macos-arm64 -VENDOR_LINUX := vendor/linux-x86_64 +if [ ! -d "$VENDOR_PATH" ]; then + echo "ERROR: $VENDOR_PATH not found!" + if [ "$DEV_MODE" = true ]; then + echo "Run 'make vendor-linux-dev' to generate dev wheels" + else + echo "Run 'make vendor-linux' or 'make vendor-macos' to generate wheels" + fi + exit 1 +fi -# ---------- Help ---------- -.PHONY: help -help: - @echo "pyhdwallet build system (macOS + Linux compatible)" - @echo "" - @echo "๐Ÿ“ฆ Vendoring (for offline/air-gapped use):" - @echo " make vendor-macos - Build macOS ARM64 wheels (requires macOS native)" - @echo " make vendor-linux - Build Linux x86_64 wheels (Docker - any OS)" - @echo " make vendor-linux-dev - Build Linux x86_64 dev wheels (includes pytest)" - @echo " make vendor-all - Build runtime wheels for both platforms" - @echo " make vendor-all-dev - Build runtime + dev wheels for all platforms" - @echo " make verify-vendor - Test offline installation from vendor/" - @echo "" - @echo "๐Ÿ”จ Binary Distribution:" - @echo " make binary - Build standalone binary for current platform" - @echo " make binary-linux - Build Linux binary via Docker (any OS)" - @echo " make binary-all - Build binaries for all platforms" - @echo "" - @echo "๐Ÿš€ Release Management:" - @echo " make release - Build complete release (binaries + vendors + checksums)" - @echo " make release-binaries - Copy binaries to releases/vX.Y.Z/" - @echo " make release-checksums - Generate SHA256SUMS for binaries" - @echo " make release-test - Test release binaries" - @echo " make clean-release - Remove all release artifacts" - @echo "" - @echo "๐Ÿ› ๏ธ Development workflow (works on macOS + Linux):" - @echo " make install - Create venv and install runtime dependencies" - @echo " make install-offline - Install runtime deps from vendor/ (offline)" - @echo " make install-dev-offline - Install runtime + dev deps from vendor/ (offline)" - @echo " make test - Run test suite" - @echo " make build-image - Build Docker image (Python 3.12)" - @echo " make wheels - Build wheels into ./$(WHEELHOUSE)" - @echo " make up - Start warm dev container" - @echo " make shell - Open shell in warm container" - @echo " make down - Stop and remove dev container" - @echo "" - @echo "๐Ÿงน Cleanup:" - @echo " make clean - Remove venv, wheelhouse (keeps vendor/)" - @echo " make clean-vendor - Remove vendor/ only" - @echo " make clean-release - Remove releases/ only" - @echo "" - @echo "โ„น๏ธ Platform Info:" - @echo " make info - Show platform detection info" - @echo "" - @echo "Platform notes:" - @echo " โ€ข vendor-macos requires native macOS (uses .venv312 with ARM64 Python)" - @echo " โ€ข vendor-linux works on any platform with Docker" - @echo " โ€ข vendor-linux-dev includes pytest for offline development" - @echo " โ€ข binary-linux works on any platform with Docker" - @echo " โ€ข All other targets work on macOS and Linux" +# Check for Python 3.12 +if ! command -v python3.12 &> /dev/null; then + echo "ERROR: Python 3.12 not found!" + echo "Please install Python 3.12:" + echo " macOS: brew install python@3.12" + echo " Linux: apt-get install python3.12 python3.12-venv" + exit 1 +fi -# ---------- Build reusable image ---------- -.PHONY: build-image -build-image: - docker build -t $(IMAGE) . - -# ---------- Vendoring for Air-Gapped Use ---------- -.PHONY: vendor-macos -vendor-macos: requirements.txt - @echo "Building macOS ARM64 wheels (native)..." - @if [ ! -f ".venv312/bin/pip" ]; then \ - echo "ERROR: .venv312 not found. Create it first:"; \ - echo " python3.12 -m venv .venv312 && source .venv312/bin/activate"; \ - exit 1; \ - fi - mkdir -p $(VENDOR_MACOS) - .venv312/bin/pip download --dest $(VENDOR_MACOS) -r requirements.txt - cd $(VENDOR_MACOS) && shasum -a 256 *.whl > SHA256SUMS - @echo "โœ“ macOS ARM64 wheels: $(VENDOR_MACOS)/" - -.PHONY: vendor-linux -vendor-linux: requirements.txt - @echo "Building Linux x86_64 wheels (Docker)..." - mkdir -p $(VENDOR_LINUX) - docker run --rm \ - --platform linux/amd64 \ - -v "$$PWD":$(WORKDIR) \ - -w $(WORKDIR) \ - python:3.12-slim \ - bash -c " \ - set -e && \ - apt-get update -qq && apt-get install -y -qq gcc g++ make libffi-dev && \ - pip install --upgrade pip && \ - pip download --dest $(VENDOR_LINUX) -r requirements.txt && \ - pip wheel --wheel-dir $(VENDOR_LINUX) --no-deps $(VENDOR_LINUX)/*.tar.gz 2>/dev/null || true && \ - rm -f $(VENDOR_LINUX)/*.tar.gz && \ - cd $(VENDOR_LINUX) && sha256sum *.whl > SHA256SUMS \ - " - @echo "โœ“ Linux x86_64 wheels: $(VENDOR_LINUX)/" - -.PHONY: vendor-linux-dev -vendor-linux-dev: requirements-dev.txt - @echo "Building Linux x86_64 dev wheels (Docker)..." - mkdir -p $(VENDOR_LINUX)-dev - docker run --rm \ - --platform linux/amd64 \ - -v "$$PWD":$(WORKDIR) \ - -w $(WORKDIR) \ - python:3.12-slim \ - bash -c " \ - set -e && \ - apt-get update -qq && apt-get install -y -qq gcc g++ make libffi-dev && \ - pip install --upgrade pip && \ - pip download --dest $(VENDOR_LINUX)-dev -r requirements-dev.txt && \ - pip wheel --wheel-dir $(VENDOR_LINUX)-dev --no-deps $(VENDOR_LINUX)-dev/*.tar.gz 2>/dev/null || true && \ - rm -f $(VENDOR_LINUX)-dev/*.tar.gz && \ - cd $(VENDOR_LINUX)-dev && sha256sum *.whl > SHA256SUMS \ - " - @echo "โœ“ Linux x86_64 dev wheels: $(VENDOR_LINUX)-dev/" - -.PHONY: vendor-all -vendor-all: vendor-macos vendor-linux - @echo "" - @echo "โœ“ All platforms vendored (runtime only):" - @echo " macOS ARM64: $(VENDOR_MACOS)/ ($$(ls $(VENDOR_MACOS)/*.whl 2>/dev/null | wc -l | xargs) wheels)" - @echo " Linux x86_64: $(VENDOR_LINUX)/ ($$(ls $(VENDOR_LINUX)/*.whl 2>/dev/null | wc -l | xargs) wheels)" - @echo "" - @echo "Commit with: git add vendor/ && git commit -m 'vendor: update wheels'" - -.PHONY: vendor-all-dev -vendor-all-dev: vendor-linux vendor-linux-dev - @echo "" - @echo "โœ“ All platform wheels (runtime + dev):" - @echo " Linux x86_64 (runtime): $(VENDOR_LINUX)/ ($$(ls $(VENDOR_LINUX)/*.whl 2>/dev/null | wc -l | xargs) wheels)" - @echo " Linux x86_64 (dev): $(VENDOR_LINUX)-dev/ ($$(ls $(VENDOR_LINUX)-dev/*.whl 2>/dev/null | wc -l | xargs) wheels)" - @echo "" - @echo "For macOS dev wheels, run on native macOS:" - @echo " python3.12 -m venv .venv312 && source .venv312/bin/activate" - @echo " pip download --dest vendor/macos-arm64-dev -r requirements-dev.txt" - -.PHONY: verify-vendor -verify-vendor: - @echo "Testing offline installation from vendor/..." - @bash -c ' \ - if [[ "$$OSTYPE" == "darwin"* ]]; then \ - PLATFORM="macos-arm64"; \ - else \ - PLATFORM="linux-x86_64"; \ - fi; \ - echo "Platform: $$PLATFORM"; \ - python3.12 -m venv .venv-verify && \ - source .venv-verify/bin/activate && \ - pip install --no-index --find-links=vendor/$$PLATFORM -r requirements.txt && \ - python src/pyhdwallet.py test && \ - echo "" && \ - echo "โœ… Vendor installation verified!" && \ - deactivate && \ - rm -rf .venv-verify \ - ' - -# ---------- Offline Installation ---------- -.PHONY: install-offline -install-offline: - @echo "Installing from vendor/ (runtime only)..." - @./install_offline.sh - -.PHONY: install-dev-offline -install-dev-offline: - @echo "Installing from vendor/ (dev mode with pytest)..." - @./install_offline.sh --dev - -# ---------- Binary Building ---------- -.PHONY: binary -binary: - @echo "๐Ÿ”จ Building binary for current platform: $(PLATFORM)-$(ARCH)..." -ifeq ($(PLATFORM),macos) - @if [ ! -f "build_binary.sh" ]; then \ - echo "โŒ build_binary.sh not found!"; \ - exit 1; \ - fi - @bash build_binary.sh +# Create venv +VENV_DIR=".venv" +if [ ! -d "$VENV_DIR" ] || [ ! -f "$VENV_DIR/bin/python3.12" ]; then + echo "Creating Python 3.12 virtual environment..." + python3.12 -m venv "$VENV_DIR" + echo "โœ“ Virtual environment created: $VENV_DIR" else - @echo "โš ๏ธ For Linux native builds, use build_binary.sh directly" - @echo " Or use: make binary-linux (builds via Docker)" -endif + echo "Using existing venv: $VENV_DIR" +fi -.PHONY: binary-linux -binary-linux: - @./build_binary_linux.sh +# Activate venv +source "$VENV_DIR/bin/activate" -.PHONY: binary-all -binary-all: - @echo "๐Ÿ—๏ธ Building binaries for all platforms..." - @echo "" - @echo "1๏ธโƒฃ Building native binary..." - @$(MAKE) binary - @echo "" - @echo "2๏ธโƒฃ Building Linux binary via Docker..." - @$(MAKE) binary-linux - @echo "" - @echo "โœ… All binaries built:" - @ls -lh dist/pyhdwallet* 2>/dev/null | awk '{print " " $$9 " (" $$5 ")"}' || echo " No binaries found" +# Verify Python version +PYTHON_VERSION=$(python --version 2>&1 | grep -oE '3\.[0-9]+') +echo "Using Python $PYTHON_VERSION from: $(which python)" -# ---------- Development Workflow ---------- -.PHONY: wheels -wheels: requirements.txt build-image - docker run --rm \ - -v "$$PWD":$(WORKDIR) \ - -w $(WORKDIR) \ - $(IMAGE) \ - bash -c " \ - pip install --upgrade pip setuptools wheel && \ - mkdir -p $(WHEELHOUSE) && \ - pip wheel -r requirements.txt -w $(WHEELHOUSE) \ - " +if [[ "$PYTHON_VERSION" != "3.12" ]]; then + echo "ERROR: Expected Python 3.12, got $PYTHON_VERSION" + exit 1 +fi -.PHONY: install -install: requirements.txt - @if [ ! -d "$(VENV_HOST)" ]; then \ - echo "Creating venv: $(VENV_HOST)"; \ - python3.12 -m venv $(VENV_HOST); \ - fi - . $(VENV_HOST)/bin/activate && \ - pip install --upgrade pip && \ - pip install -r requirements.txt && \ - echo "โœ“ Virtual environment ready: $(VENV_HOST)" +# Verify checksums +if [ -f "$VENDOR_PATH/SHA256SUMS" ]; then + echo "" + echo "Verifying checksums..." + (cd "$VENDOR_PATH" && sha256sum -c SHA256SUMS --quiet) || { + echo "ERROR: Checksum verification failed!" + exit 1 + } + echo "โœ“ Checksums verified" +fi -.PHONY: test -test: - @if [ ! -d "$(VENV_HOST)" ]; then \ - echo "ERROR: Run 'make install' first"; \ - exit 1; \ - fi - . $(VENV_HOST)/bin/activate && \ - pytest -v tests/test_vectors.py && \ - python src/pyhdwallet.py test +# Install +echo "" +if [ "$DEV_MODE" = true ]; then + echo "Installing from $VENDOR_PATH (includes dev dependencies)..." + pip install --upgrade pip --quiet + pip install --no-index --find-links="$VENDOR_PATH" -r requirements-dev.txt +else + echo "Installing from $VENDOR_PATH..." + pip install --upgrade pip --quiet + pip install --no-index --find-links="$VENDOR_PATH" -r requirements.txt +fi -# ---------- Warm container lifecycle ---------- -.PHONY: up -up: build-image - docker run -dit \ - -v "$$PWD":$(WORKDIR) \ - -w $(WORKDIR) \ - --name $(CONTAINER) \ - $(IMAGE) \ - bash +# Test +echo "" +echo "Running tests..." -.PHONY: shell -shell: - docker exec -it $(CONTAINER) bash +if [ "$DEV_MODE" = true ]; then + # Run full test suite if pytest available + if python -c "import pytest" >/dev/null 2>&1; then + python -m pytest -v tests/test_vectors.py || { + echo "ERROR: Tests failed!" + exit 1 + } + else + echo "โš ๏ธ pytest not found in dev install!" + fi +else + # Only mention pytest in production mode + echo "โš ๏ธ Skipping pytest (use --dev for full test suite)" +fi -.PHONY: down -down: - - docker rm -f $(CONTAINER) +echo "" +echo "Running built-in smoke test..." +python src/pyhdwallet.py test || { + echo "ERROR: Smoke test failed!" + exit 1 +} -# ---------- Cleanup ---------- -.PHONY: clean-vendor -clean-vendor: - rm -rf vendor/ - -.PHONY: clean -clean: down - rm -rf $(VENV_HOST) $(WHEELHOUSE) .venv-verify .venv-offline-test - rm -rf dist/ build/ *.spec src/pyhdwallet_frozen.py - find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true - find . -type d -name "*.egg-info" -exec rm -rf {} + 2>/dev/null || true - # NOTE: vendor/ is kept (use 'make clean-vendor' to remove) - -# ---------- Platform-Aware Operations ---------- -.PHONY: info -info: - @echo "Platform Information:" - @echo " OS: $(PLATFORM)" - @echo " Architecture: $(ARCH)" - @echo " Vendor dir: $(VENDOR_DIR)" - @echo " Python: $(shell python3 --version 2>/dev/null || echo 'not found')" - @echo " Docker: $(shell docker --version 2>/dev/null || echo 'not found')" - -# ---------- Release Management ---------- -VERSION := v1.1.0 -RELEASE_DIR := releases/$(VERSION) - -.PHONY: release-prep -release-prep: - @echo "๐Ÿ“ฆ Preparing release $(VERSION)..." - @mkdir -p $(RELEASE_DIR) - -.PHONY: release-binaries -release-binaries: release-prep binary binary-linux - @echo "๐Ÿ“ฆ Copying binaries to $(RELEASE_DIR)..." - @cp dist/pyhdwallet $(RELEASE_DIR)/pyhdwallet-macos-arm64 - @cp dist/pyhdwallet-linux $(RELEASE_DIR)/pyhdwallet-linux-x86_64 - @echo "โœ… Binaries copied" - -.PHONY: release-checksums -release-checksums: release-binaries - @echo "๐Ÿ” Generating checksums..." - @cd $(RELEASE_DIR) && shasum -a 256 pyhdwallet-* > SHA256SUMS - @echo "โœ… Checksums generated:" - @cat $(RELEASE_DIR)/SHA256SUMS - -.PHONY: release-vendors -release-vendors: release-prep vendor-all - @echo "๐Ÿ“ฆ Copying vendor wheels to $(RELEASE_DIR)..." - @mkdir -p $(RELEASE_DIR)/vendor - @cp -r vendor/macos-arm64 $(RELEASE_DIR)/vendor/ - @cp -r vendor/linux-x86_64 $(RELEASE_DIR)/vendor/ - @echo "โœ… Vendor wheels copied" - -.PHONY: release -release: release-checksums - @echo "" - @echo "๐ŸŽ‰ Release $(VERSION) binaries ready!" - @echo "" - @if [ -d ".venv312" ]; then \ - echo "๐Ÿ“ฆ Building vendor wheels..."; \ - $(MAKE) release-vendors; \ - else \ - echo "โš ๏ธ Skipping vendor wheels (.venv312 not found)"; \ - echo " To include vendors: python3.12 -m venv .venv312 && make release-vendors"; \ - fi - @echo "" - @echo "Contents:" - @ls -lh $(RELEASE_DIR)/ | tail -n +2 - @echo "" - @cat $(RELEASE_DIR)/SHA256SUMS - @echo "" - @echo "Next steps:" - @echo " 1. Test: make release-test" - @echo " 2. Tag: git tag -a $(VERSION) -m 'Release $(VERSION)'" - @echo " 3. Push: git push origin $(VERSION)" - -.PHONY: release-test -release-test: - @echo "๐Ÿงช Testing release binaries..." - @echo "" - @echo "Testing macOS binary:" - @$(RELEASE_DIR)/pyhdwallet-macos-arm64 test || echo "โš ๏ธ macOS binary test skipped (wrong platform)" - @echo "" - @echo "Testing Linux binary (via Docker):" - @docker run --rm --platform linux/amd64 \ - -v "$$PWD/$(RELEASE_DIR)":/binaries \ - ubuntu:22.04 \ - /binaries/pyhdwallet-linux-x86_64 test - -.PHONY: clean-release -clean-release: - @echo "๐Ÿงน Cleaning release artifacts..." - @rm -rf releases/ - @echo "โœ… Release artifacts cleaned" +echo "" +echo "==========================================" +echo "โœ“ Installation complete and verified!" +echo "==========================================" +echo "" +echo "Virtual environment: $VENV_DIR" +echo "Python version: $(python --version)" +if [ "$DEV_MODE" = true ]; then + echo "Mode: Development (pytest installed)" +else + echo "Mode: Production (runtime only)" +fi +echo "" +echo "To activate this environment:" +echo " source $VENV_DIR/bin/activate" +echo "" +if [ "$DEV_MODE" = false ]; then + echo "For development with pytest:" + echo " ./install_offline.sh --dev" + echo "" +fi +echo "Generate a wallet:" +echo " python src/pyhdwallet.py gen --help"