From 001fb76f3974f1d67bb9d5585b2990420492fd78 Mon Sep 17 00:00:00 2001 From: Patrick Dawkins Date: Fri, 24 Oct 2025 23:36:47 +0100 Subject: [PATCH 1/4] feat: upgrade static-php-cli submodule to v2.7.5 Update the static-php-cli submodule from commit 4c55f4a2 to v2.7.5 (c5ae719b). Changes made to adapt to v2.7.5: - Replace legacy Docker build script approach with spc-alpine-docker tool. - Add ext/craft.yml to configure PHP extensions (curl, filter, openssl, pcntl, phar, posix, zlib). - Update Makefile to use new build command via spc-alpine-docker. The new version uses a unified craft.yml configuration format and bin/spc tool instead of the legacy docker/ directory with manual build scripts. Co-Authored-By: Claude --- Dockerfile.php | 80 ---------------------------------------------- Makefile | 14 +++----- ext/craft.yml | 33 +++++++++++++++++++ ext/extensions.txt | 44 ------------------------- ext/static-php-cli | 2 +- 5 files changed, 38 insertions(+), 135 deletions(-) delete mode 100755 Dockerfile.php create mode 100644 ext/craft.yml delete mode 100755 ext/extensions.txt diff --git a/Dockerfile.php b/Dockerfile.php deleted file mode 100755 index cae04c1c..00000000 --- a/Dockerfile.php +++ /dev/null @@ -1,80 +0,0 @@ -FROM alpine:3.16 - -# define script basic information -# Version of this Dockerfile -ENV SCRIPT_VERSION=1.5.1 -# Download address uses backup address - -ARG USE_BACKUP_ADDRESS -ARG PHP_VERSION - -# (if downloading slowly, consider set it to yes) -ENV USE_BACKUP="${USE_BACKUP_ADDRESS}" - -# APK repositories mirror address, if u r not in China, consider set USE_BACKUP=yes to boost -ENV LINK_APK_REPO='mirrors.ustc.edu.cn' -ENV LINK_APK_REPO_BAK='dl-cdn.alpinelinux.org' - -RUN if [ "${USE_BACKUP}" = "" ]; then \ - export USE_BACKUP="no" ; \ - fi - -RUN if [ "${USE_BACKUP}" = "yes" ]; then \ - echo "Using backup original address..." ; \ - else \ - echo "Using mirror address..." && \ - sed -i 's/dl-cdn.alpinelinux.org/'${LINK_APK_REPO}'/g' /etc/apk/repositories ; \ - fi - -# build requirements -RUN apk add bash file wget cmake gcc g++ jq autoconf git libstdc++ linux-headers make m4 libgcc binutils ncurses dialog > /dev/null -# php zlib dependencies -RUN apk add zlib-dev zlib-static > /dev/null -# php mbstring dependencies -RUN apk add oniguruma-dev > /dev/null -# php openssl dependencies -RUN apk add openssl-libs-static openssl-dev openssl > /dev/null -# php gd dependencies -RUN apk add libpng-dev libpng-static > /dev/null -# curl c-ares dependencies -RUN apk add c-ares-static c-ares-dev > /dev/null -# php event dependencies -RUN apk add libevent libevent-dev libevent-static > /dev/null -# php sqlite3 dependencies -RUN apk add sqlite sqlite-dev sqlite-libs sqlite-static > /dev/null -# php libzip dependencies -RUN apk add bzip2-dev bzip2-static bzip2 > /dev/null -# php micro ffi dependencies -RUN apk add libffi libffi-dev > /dev/null -# php gd event parent dependencies -RUN apk add zstd-static > /dev/null -# php readline dependencies -RUN apk add readline-static ncurses-static readline-dev > /dev/null - -RUN mkdir /app - -WORKDIR /app - -COPY ./* /app/ - -RUN chmod +x /app/*.sh - -RUN ./download.sh swoole ${USE_BACKUP} && \ - ./download.sh inotify ${USE_BACKUP} && \ - ./download.sh mongodb ${USE_BACKUP} && \ - ./download.sh event ${USE_BACKUP} && \ - ./download.sh redis ${USE_BACKUP} && \ - ./download.sh libxml2 ${USE_BACKUP} && \ - ./download.sh xz ${USE_BACKUP} && \ - ./download.sh curl ${USE_BACKUP} && \ - ./download.sh libzip ${USE_BACKUP} && \ - ./download-git.sh dixyes/phpmicro phpmicro ${USE_BACKUP} - -RUN ./compile-deps.sh -RUN echo -e "#!/usr/bin/env bash\n/app/compile-php.sh \$@" > /bin/build-php && chmod +x /bin/build-php - -RUN /bin/build-php no-mirror $PHP_VERSION all /dist - -FROM scratch -ARG GOARCH -COPY --from=0 /dist/php /php_linux_$GOARCH diff --git a/Makefile b/Makefile index 99abc6e6..b9f72407 100644 --- a/Makefile +++ b/Makefile @@ -37,16 +37,10 @@ internal/legacy/archives/php_darwin_$(GOARCH): rm -rf $(GOOS) internal/legacy/archives/php_linux_$(GOARCH): - cp ext/extensions.txt ext/static-php-cli/docker - docker buildx build \ - --build-arg GOARCH=$(GOARCH) \ - --build-arg PHP_VERSION=$(PHP_VERSION) \ - --build-arg USE_BACKUP_ADDRESS=yes \ - --file=./Dockerfile.php \ - --platform=linux/$(GOARCH) \ - --output=type=local,dest=./internal/legacy/archives/ \ - --progress=plain \ - ext/static-php-cli/docker + mkdir -p internal/legacy/archives + cd ext/static-php-cli && SPC_USE_ARCH=$(GOARCH) ./bin/spc-alpine-docker download --with-php=$(PHP_VERSION) --for-extensions=curl,filter,openssl,pcntl,phar,posix,zlib + cd ext/static-php-cli && SPC_USE_ARCH=$(GOARCH) ./bin/spc-alpine-docker build curl,filter,openssl,pcntl,phar,posix,zlib --build-cli + cp ext/static-php-cli/buildroot/bin/php $(PHP_BINARY_PATH) PHP_WINDOWS_REMOTE_FILENAME := "php-$(PHP_VERSION)-nts-Win32-vs16-x64.zip" internal/legacy/archives/php_windows.zip: diff --git a/ext/craft.yml b/ext/craft.yml new file mode 100644 index 00000000..b028b161 --- /dev/null +++ b/ext/craft.yml @@ -0,0 +1,33 @@ +# craft.yml configuration for building PHP CLI for Upsun CLI +# This file configures static-php-cli v2.7.5+ to build a minimal PHP binary + +php-version: "8.2" + +extensions: + - curl + - filter + - openssl + - pcntl + - phar + - posix + - zlib + +libs: [] + +sapi: + - cli + +build-options: + with-clean: false + with-suggested-libs: false + with-upx-pack: true + with-strip-php: true + +download-options: + prefer-pre-built: true + retry: 5 + +craft-options: + doctor: true + download: true + build: true diff --git a/ext/extensions.txt b/ext/extensions.txt deleted file mode 100755 index 691b457e..00000000 --- a/ext/extensions.txt +++ /dev/null @@ -1,44 +0,0 @@ -# Start with '#' is comments -# Start with '^' is deselecting extensions, which is not installed as default -# Each line just leave the extension name or ^ character - -^bcmath -^calendar -^ctype -curl -^dom -^event -^exif -^fileinfo -filter -^gd -^hash -^iconv -^inotify -^json -^libxml -^mbstring -^mongodb -^mysqlnd -openssl -pcntl -^pdo -^pdo_mysql -^pdo_sqlite -phar -posix -^protobuf -^readline -^redis -^shmop -^simplexml -^soap -^sockets -^sqlite3 -^swoole -^tokenizer -^xml -^xmlreader -^xmlwriter -zlib -^zip diff --git a/ext/static-php-cli b/ext/static-php-cli index 4c55f4a2..c5ae719b 160000 --- a/ext/static-php-cli +++ b/ext/static-php-cli @@ -1 +1 @@ -Subproject commit 4c55f4a22be0b2e130af023ef7593bcefa78314a +Subproject commit c5ae719b9c7bdb811d8f94eff42b3827e5cde1fc From d5c7f5eac909143e18748d7598b3f858f659b8bb Mon Sep 17 00:00:00 2001 From: Patrick Dawkins Date: Tue, 11 Nov 2025 20:51:59 +0000 Subject: [PATCH 2/4] refactor: use craft command for PHP build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use static-php-cli's craft command instead of separate download and build commands. This eliminates the duplication of the extensions list and aligns with the configuration-driven approach in craft.yml. Also remove invalid with-strip-php option from craft.yml (stripping is the default behavior). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- Makefile | 4 ++-- ext/craft.yml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index b9f72407..6e8cc2e6 100644 --- a/Makefile +++ b/Makefile @@ -38,8 +38,8 @@ internal/legacy/archives/php_darwin_$(GOARCH): internal/legacy/archives/php_linux_$(GOARCH): mkdir -p internal/legacy/archives - cd ext/static-php-cli && SPC_USE_ARCH=$(GOARCH) ./bin/spc-alpine-docker download --with-php=$(PHP_VERSION) --for-extensions=curl,filter,openssl,pcntl,phar,posix,zlib - cd ext/static-php-cli && SPC_USE_ARCH=$(GOARCH) ./bin/spc-alpine-docker build curl,filter,openssl,pcntl,phar,posix,zlib --build-cli + cp ext/craft.yml ext/static-php-cli/craft.yml + cd ext/static-php-cli && SPC_USE_ARCH=$(GOARCH) ./bin/spc-alpine-docker craft craft.yml cp ext/static-php-cli/buildroot/bin/php $(PHP_BINARY_PATH) PHP_WINDOWS_REMOTE_FILENAME := "php-$(PHP_VERSION)-nts-Win32-vs16-x64.zip" diff --git a/ext/craft.yml b/ext/craft.yml index b028b161..99ab6035 100644 --- a/ext/craft.yml +++ b/ext/craft.yml @@ -21,7 +21,6 @@ build-options: with-clean: false with-suggested-libs: false with-upx-pack: true - with-strip-php: true download-options: prefer-pre-built: true From 7015c4745b5caab46335bcc68e16b7e4a086c4fd Mon Sep 17 00:00:00 2001 From: Patrick Dawkins Date: Tue, 11 Nov 2025 20:55:35 +0000 Subject: [PATCH 3/4] docs: add comments to craft-options in craft.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document craft-options based on static-php-cli documentation: doctor checks the environment, download fetches php-src and libraries, and build compiles the static binary. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- ext/craft.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/craft.yml b/ext/craft.yml index 99ab6035..4880b97d 100644 --- a/ext/craft.yml +++ b/ext/craft.yml @@ -27,6 +27,6 @@ download-options: retry: 5 craft-options: - doctor: true - download: true - build: true + doctor: true # Check environment and automatically fix when possible. + download: true # Download source code (php-src and libraries). + build: true # Build the static PHP binary. From bd4d6592116139818bda8d2132dbc437806b2192 Mon Sep 17 00:00:00 2001 From: Patrick Dawkins Date: Mon, 29 Dec 2025 17:02:14 -0500 Subject: [PATCH 4/4] Adapt for external PHP builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PHP binaries are now downloaded from upsun/cli-php-builds releases instead of being built locally. This decouples PHP builds from CLI releases and simplifies the build process. Changes: - Makefile: Replace local build targets with download targets - php_manager_windows.go: Simplify to use static binary (no ZIP/DLLs) - CLAUDE.md: Update build documentation - Remove ext/ submodule and build-php-brew.sh 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .gitmodules | 3 - CLAUDE.md | 160 +++++++++++++++++++++++++ Makefile | 62 +++++----- build-php-brew.sh | 44 ------- ext/craft.yml | 32 ----- ext/static-php-cli | 1 - internal/legacy/php_manager_windows.go | 82 +------------ 7 files changed, 200 insertions(+), 184 deletions(-) delete mode 100644 .gitmodules create mode 100644 CLAUDE.md delete mode 100644 build-php-brew.sh delete mode 100644 ext/craft.yml delete mode 160000 ext/static-php-cli diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e1a3ca85..00000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "ext/static-php-cli"] - path = ext/static-php-cli - url = https://github.com/crazywhalecc/static-php-cli diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..478b0fd1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,160 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +The Upsun CLI is a Go-based command-line interface for Upsun (formerly Platform.sh). The CLI is a hybrid system that wraps a legacy PHP CLI while providing new Go-based commands. It supports multiple vendors through build tags and configuration files. + +## Build and Test Commands + +Build a single binary for your platform: +```bash +make single +``` + +Build a snapshot for all platforms: +```bash +make snapshot +``` + +Run tests: +```bash +make test +# or directly: +GOEXPERIMENT=jsonv2 go test -v -race -cover -count=1 ./... +``` + +Run linters: +```bash +make lint +# or individual linters: +make lint-gomod +make lint-golangci +``` + +Format code: +```bash +go fmt ./... +``` + +Tidy dependencies: +```bash +go mod tidy +``` + +Run a single test: +```bash +go test -v -run TestName ./path/to/package +``` + +## Architecture + +### Hybrid CLI System + +The CLI operates as a wrapper around a legacy PHP CLI: +- Go layer: Handles new commands (init, list, version, config:install, project:convert) and core infrastructure +- PHP layer: Legacy commands are proxied through `internal/legacy/CLIWrapper` +- The PHP CLI (platform.phar) is embedded at build time via go:embed + +### Key Components + +**Entry Point**: `cmd/platform/main.go` +- Loads configuration from YAML (embedded or external) +- Sets up Viper for environment variable handling +- Delegates to commands package + +**Commands**: `commands/` +- `root.go`: Root command that sets up the Cobra CLI and delegates to legacy CLI when needed +- Native Go commands: init, list, version, config:install, project:convert, completion +- Unrecognized commands are passed to the legacy PHP CLI + +**Configuration**: `internal/config/` +- `schema.go`: Config struct definition with validation tags +- Supports vendorization through embedded YAML configs (config_upsun.go, config_platformsh.go, config_vendor.go) +- Uses build tags to select which config is embedded +- Config can be loaded from external files for testing/development + +**Legacy Integration**: `internal/legacy/` +- `legacy.go`: CLIWrapper that manages PHP binary and phar execution +- PHP binaries are embedded per platform via go:embed and build tags +- Uses file locking to prevent concurrent initialization +- Copies PHP binary and phar to cache directory on first run + +**API Client**: `internal/api/` +- HTTP client for interacting with Platform.sh/Upsun API +- Handles authentication, organizations, and resource management + +**Authentication**: `internal/auth/` +- JWT handling and OAuth2 flow +- Custom transport for API authentication + +**Project Initialization**: `internal/init/` +- AI-powered project configuration generation +- Integrates with whatsun library for codebase analysis + +### Build System + +**Multi-Vendor Support**: +- Uses Go build tags (platform, upsun, vendor) to compile different binaries +- Configuration is embedded at compile time +- GoReleaser builds multiple variants (platform, upsun, vendor-specific) + +**PHP Binary Handling**: +- PHP binaries are downloaded from [upsun/cli-php-builds](https://github.com/upsun/cli-php-builds) releases +- All platforms use static binaries built with [static-php-cli](https://github.com/crazywhalecc/static-php-cli) +- Supported platforms: linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64 +- Extensions included: curl, filter, openssl, pcntl (Unix), phar, posix (Unix), zlib +- Windows requires `cacert.pem` for OpenSSL (embedded separately) + +**Downloading PHP Binaries**: +```bash +# Download PHP for current platform only (for development) +make php + +# Download all PHP binaries (for release builds) +make download-php +``` + +**Upgrading PHP Version**: +1. Trigger the build workflow at [upsun/cli-php-builds](https://github.com/upsun/cli-php-builds/actions) with the new PHP version +2. Update `PHP_VERSION` in the Makefile +3. Run `make php` to download the new binary +4. Test and release + +## Development Notes + +### Testing + +Tests use github.com/stretchr/testify for assertions. Table-driven tests are preferred with a "cases" slice containing simple test case structs. + +### Configuration + +The CLI uses Viper for configuration. Environment variables use the prefix defined in the config (UPSUN_CLI_ or PLATFORM_CLI_). The prefix is set in the config YAML. + +### Legacy CLI Interaction + +When the root command receives arguments it doesn't recognize, it passes them to the legacy PHP CLI via CLIWrapper.Exec(). The PHP binary and phar are extracted to a cache directory on first use. + +### Vendorization + +To build a vendor-specific CLI: +```bash +make vendor-snapshot VENDOR_NAME='Vendor Name' VENDOR_BINARY='vendorcli' +make vendor-release VENDOR_NAME='Vendor Name' VENDOR_BINARY='vendorcli' +``` + +This requires a config file at `internal/config/embedded-config.yaml` (downloaded at build time). + +### Version Information + +Version information is injected at build time via ldflags: +- `internal/config.Version`: Git tag/version +- `internal/config.Commit`: Git commit hash +- `internal/config.Date`: Build date +- `internal/legacy.PHPVersion`: PHP version embedded +- `internal/legacy.LegacyCLIVersion`: Legacy CLI version embedded + +### Update Checks + +The CLI checks for updates from GitHub releases (when Wrapper.GitHubRepo is set in config). This runs in a background goroutine and prints a message after command execution. diff --git a/Makefile b/Makefile index 6e8cc2e6..411fc355 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PHP_VERSION = 8.2.29 +PHP_VERSION = 8.4.16 LEGACY_CLI_VERSION = 4.28.2 GORELEASER_ID ?= upsun @@ -7,10 +7,6 @@ ifeq ($(GOOS), darwin) GORELEASER_ID=$(GORELEASER_ID)-macos endif -# The OpenSSL version must be compatible with the PHP version. -# See: https://www.php.net/manual/en/openssl.requirements.php -OPENSSL_VERSION = 1.1.1t - GOOS := $(shell uname -s | tr '[:upper:]' '[:lower:]') GOARCH := $(shell uname -m) ifeq ($(GOARCH), x86_64) @@ -20,45 +16,55 @@ ifeq ($(GOARCH), aarch64) GOARCH=arm64 endif -PHP_BINARY_PATH := internal/legacy/archives/php_$(GOOS)_$(GOARCH) VERSION := $(shell git describe --always) # Tooling versions GORELEASER_VERSION=v2.12.0 -internal/legacy/archives/platform.phar: - curl -L https://github.com/platformsh/legacy-cli/releases/download/v$(LEGACY_CLI_VERSION)/platform.phar -o internal/legacy/archives/platform.phar +# PHP binaries are downloaded from cli-php-builds releases. +# See: https://github.com/upsun/cli-php-builds +PHP_BUILDS_REPO = upsun/cli-php-builds +PHP_RELEASE_URL = https://github.com/$(PHP_BUILDS_REPO)/releases/download/php-$(PHP_VERSION) -internal/legacy/archives/php_windows_amd64: internal/legacy/archives/php_windows.zip internal/legacy/archives/cacert.pem +internal/legacy/archives/platform.phar: + mkdir -p internal/legacy/archives + curl -fSL https://github.com/platformsh/legacy-cli/releases/download/v$(LEGACY_CLI_VERSION)/platform.phar -o internal/legacy/archives/platform.phar +# Download PHP binary for the current platform. internal/legacy/archives/php_darwin_$(GOARCH): - bash build-php-brew.sh $(GOOS) $(PHP_VERSION) $(OPENSSL_VERSION) - mv -f $(GOOS)/php-$(PHP_VERSION)/sapi/cli/php $(PHP_BINARY_PATH) - rm -rf $(GOOS) + mkdir -p internal/legacy/archives + curl -fSL "$(PHP_RELEASE_URL)/php-$(PHP_VERSION)-darwin-$(GOARCH)" -o $@ + chmod +x $@ internal/legacy/archives/php_linux_$(GOARCH): mkdir -p internal/legacy/archives - cp ext/craft.yml ext/static-php-cli/craft.yml - cd ext/static-php-cli && SPC_USE_ARCH=$(GOARCH) ./bin/spc-alpine-docker craft craft.yml - cp ext/static-php-cli/buildroot/bin/php $(PHP_BINARY_PATH) - -PHP_WINDOWS_REMOTE_FILENAME := "php-$(PHP_VERSION)-nts-Win32-vs16-x64.zip" -internal/legacy/archives/php_windows.zip: - ( \ - set -e ;\ - mkdir -p internal/legacy/archives ;\ - cd internal/legacy/archives ;\ - curl -f "https://windows.php.net/downloads/releases/$(PHP_WINDOWS_REMOTE_FILENAME)" > php_windows.zip ;\ - curl -f https://windows.php.net/downloads/releases/sha256sum.txt | grep "$(PHP_WINDOWS_REMOTE_FILENAME)" | sed s/"$(PHP_WINDOWS_REMOTE_FILENAME)"/"php_windows.zip"/g > php_windows.zip.sha256 ;\ - sha256sum -c php_windows.zip.sha256 ;\ - ) + curl -fSL "$(PHP_RELEASE_URL)/php-$(PHP_VERSION)-linux-$(GOARCH)" -o $@ + chmod +x $@ + +internal/legacy/archives/php_windows_amd64: internal/legacy/archives/php_windows.exe internal/legacy/archives/cacert.pem + +internal/legacy/archives/php_windows.exe: + mkdir -p internal/legacy/archives + curl -fSL "$(PHP_RELEASE_URL)/php-$(PHP_VERSION)-windows-amd64.exe" -o $@ .PHONY: internal/legacy/archives/cacert.pem internal/legacy/archives/cacert.pem: mkdir -p internal/legacy/archives - curl https://curl.se/ca/cacert.pem > internal/legacy/archives/cacert.pem + curl -fSL https://curl.se/ca/cacert.pem -o internal/legacy/archives/cacert.pem -php: $(PHP_BINARY_PATH) +# Download all PHP binaries (for release builds). +.PHONY: download-php +download-php: + mkdir -p internal/legacy/archives + curl -fSL "$(PHP_RELEASE_URL)/php-$(PHP_VERSION)-linux-amd64" -o internal/legacy/archives/php_linux_amd64 + curl -fSL "$(PHP_RELEASE_URL)/php-$(PHP_VERSION)-linux-arm64" -o internal/legacy/archives/php_linux_arm64 + curl -fSL "$(PHP_RELEASE_URL)/php-$(PHP_VERSION)-darwin-amd64" -o internal/legacy/archives/php_darwin_amd64 + curl -fSL "$(PHP_RELEASE_URL)/php-$(PHP_VERSION)-darwin-arm64" -o internal/legacy/archives/php_darwin_arm64 + curl -fSL "$(PHP_RELEASE_URL)/php-$(PHP_VERSION)-windows-amd64.exe" -o internal/legacy/archives/php_windows.exe + curl -fSL https://curl.se/ca/cacert.pem -o internal/legacy/archives/cacert.pem + chmod +x internal/legacy/archives/php_linux_* internal/legacy/archives/php_darwin_* + +php: internal/legacy/archives/php_$(GOOS)_$(GOARCH) .PHONY: goreleaser goreleaser: diff --git a/build-php-brew.sh b/build-php-brew.sh deleted file mode 100644 index f7a3a702..00000000 --- a/build-php-brew.sh +++ /dev/null @@ -1,44 +0,0 @@ -set -ex - -DIR=$1 -PHP_VERSION=$2 -OPENSSL_VERSION=$3 - -brew install bison pkg-config coreutils autoconf - -SSL_DIR_PATH=$(pwd)/"$DIR"/ssl -mkdir -p "$SSL_DIR_PATH" - -curl -LfSsl https://www.openssl.org/source/openssl-"$OPENSSL_VERSION".tar.gz | tar xzf - -C "$DIR" -cd "$DIR"/openssl-"$OPENSSL_VERSION" - -./config no-shared --prefix="$SSL_DIR_PATH" --openssldir="$SSL_DIR_PATH" -make -make install - -cd ../.. -curl -fSsl https://www.php.net/distributions/php-"$PHP_VERSION".tar.gz | tar xzf - -C "$DIR" -cd "$DIR"/php-"$PHP_VERSION" - -rm -f sapi/cli/php - -./buildconf --force -./configure \ - --disable-shared \ - --enable-embed=static \ - --enable-filter \ - --enable-pcntl \ - --enable-phar \ - --enable-posix \ - --enable-static \ - --enable-sysvmsg \ - --with-curl \ - --with-openssl \ - --with-pear=no \ - --without-pcre-jit \ - --with-zlib \ - --disable-all \ -OPENSSL_CFLAGS="-I$SSL_DIR_PATH/include" \ -OPENSSL_LIBS="-L$SSL_DIR_PATH/lib -lssl -lcrypto" - -make -j"$(nproc)" cli diff --git a/ext/craft.yml b/ext/craft.yml deleted file mode 100644 index 4880b97d..00000000 --- a/ext/craft.yml +++ /dev/null @@ -1,32 +0,0 @@ -# craft.yml configuration for building PHP CLI for Upsun CLI -# This file configures static-php-cli v2.7.5+ to build a minimal PHP binary - -php-version: "8.2" - -extensions: - - curl - - filter - - openssl - - pcntl - - phar - - posix - - zlib - -libs: [] - -sapi: - - cli - -build-options: - with-clean: false - with-suggested-libs: false - with-upx-pack: true - -download-options: - prefer-pre-built: true - retry: 5 - -craft-options: - doctor: true # Check environment and automatically fix when possible. - download: true # Download source code (php-src and libraries). - build: true # Build the static PHP binary. diff --git a/ext/static-php-cli b/ext/static-php-cli deleted file mode 160000 index c5ae719b..00000000 --- a/ext/static-php-cli +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c5ae719b9c7bdb811d8f94eff42b3827e5cde1fc diff --git a/internal/legacy/php_manager_windows.go b/internal/legacy/php_manager_windows.go index 5b33043d..54d035a6 100644 --- a/internal/legacy/php_manager_windows.go +++ b/internal/legacy/php_manager_windows.go @@ -1,102 +1,32 @@ package legacy import ( - "archive/zip" - "bytes" _ "embed" - "fmt" - "io" - "os" "path/filepath" - "runtime" - "strings" - - "golang.org/x/sync/errgroup" "github.com/platformsh/cli/internal/file" ) -//go:embed archives/php_windows.zip +//go:embed archives/php_windows.exe var phpCLI []byte //go:embed archives/cacert.pem var caCert []byte func (m *phpManagerPerOS) copy() error { - destDir := filepath.Join(m.cacheDir, "php") - - r, err := zip.NewReader(bytes.NewReader(phpCLI), int64(len(phpCLI))) - if err != nil { - return fmt.Errorf("could not open zip reader: %w", err) - } - - g := errgroup.Group{} - g.SetLimit(runtime.GOMAXPROCS(0)) - for _, f := range r.File { - g.Go(func() error { - return copyZipFile(f, destDir) - }) - } - if err := g.Wait(); err != nil { + if err := file.WriteIfNeeded(m.binPath(), phpCLI, 0o755); err != nil { return err } - - if err := file.WriteIfNeeded(filepath.Join(destDir, "extras", "cacert.pem"), caCert, 0o644); err != nil { - return err - } - - return nil + // Write cacert.pem for OpenSSL CA bundle (Windows needs this explicitly). + return file.WriteIfNeeded(filepath.Join(m.cacheDir, "cacert.pem"), caCert, 0o644) } func (m *phpManagerPerOS) binPath() string { - return filepath.Join(m.cacheDir, "php", "php.exe") + return filepath.Join(m.cacheDir, "php.exe") } func (m *phpManagerPerOS) settings() []string { return []string{ - "extension=" + filepath.Join(m.cacheDir, "php", "ext", "php_curl.dll"), - "extension=" + filepath.Join(m.cacheDir, "php", "ext", "php_openssl.dll"), - "openssl.cafile=" + filepath.Join(m.cacheDir, "php", "extras", "cacert.pem"), - } -} - -// copyZipFile extracts a file from the Zip to the destination directory. -// If the file already exists and has the correct size, it will be skipped. -func copyZipFile(f *zip.File, destDir string) error { - destPath := filepath.Join(destDir, f.Name) - if !strings.HasPrefix(destPath, filepath.Clean(destDir)+string(os.PathSeparator)) { - return fmt.Errorf("invalid file path: %s", destPath) + "openssl.cafile=" + filepath.Join(m.cacheDir, "cacert.pem"), } - - if f.FileInfo().IsDir() { - if err := os.MkdirAll(destPath, 0755); err != nil { - return fmt.Errorf("could not create extracted directory %s: %w", destPath, err) - } - return nil - } - - if existingFileInfo, err := os.Lstat(destPath); err == nil && uint64(existingFileInfo.Size()) == f.UncompressedSize64 { - return nil - } - - if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil { - return fmt.Errorf("could not create parent directory for extracted file %s: %w", destPath, err) - } - - rc, err := f.Open() - if err != nil { - return fmt.Errorf("could not open file in zip archive %s: %w", f.Name, err) - } - defer rc.Close() - - b, err := io.ReadAll(rc) - if err != nil { - return fmt.Errorf("could not extract zipped file %s: %w", f.Name, err) - } - - if err := file.Write(destPath, b, f.Mode()); err != nil { - return fmt.Errorf("could not copy extracted file %s: %w", destPath, err) - } - - return nil }