From 549d883bbc710ffce7e403c3063d718ae286dead Mon Sep 17 00:00:00 2001 From: Alex Palaistras Date: Fri, 6 Oct 2017 12:39:05 +0100 Subject: [PATCH] Add Dockerfiles, Makefile for testing against isolated environment This commit adds a Dockerfile for PHP 5.6.x and PHP 7.1.x versions, allowing for tests, package builds etc. to run against an isolated, controlled environment. PHP is currently built as a shared library, in the future we may build as a static library to allow bundling with Go applications. Also included is a Makefile, containing targets for common operations, such as testing, building packages etc. Two undocumented targets related to Docker are included, `docker-image` and `docker-test`. Moving these as documented targets is a future task. --- .gitignore | 4 ++ Dockerfile.php5 | 60 ++++++++++++++++++++ Dockerfile.php7 | 60 ++++++++++++++++++++ Makefile | 147 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile.php5 create mode 100644 Dockerfile.php7 create mode 100644 Makefile diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f55dfdc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.build +*.deb +*.tar.xz +*.out diff --git a/Dockerfile.php5 b/Dockerfile.php5 new file mode 100644 index 0000000..6e309bd --- /dev/null +++ b/Dockerfile.php5 @@ -0,0 +1,60 @@ +FROM debian:stable-slim + +ENV PHP_VERSION="5.6.31" +ENV PHP_URL="https://secure.php.net/get/php-${PHP_VERSION}.tar.xz/from/this/mirror" PHP_ASC_URL="https://secure.php.net/get/php-${PHP_VERSION}.tar.xz.asc/from/this/mirror" + +ENV PHP_BASE_DIR="/tmp/php" +ENV PHP_SRC_DIR="${PHP_BASE_DIR}/src" + +ENV PHP_LDFLAGS="-Wl,-O1 -Wl,--hash-style=both -pie" +ENV PHP_CFLAGS="-fstack-protector-strong -fpic -fpie -O2" +ENV PHP_CPPFLAGS="${PHP_CFLAGS}" + +ENV GPG_KEYS="0BD78B5F97500D450838F95DFE857D9A90D90EC1 6E4F6AB321FDC07F2C332E3AC2BF0BC433CFC8B3" +ENV PHP_SHA256="c464af61240a9b7729fabe0314cdbdd5a000a4f0c9bd201f89f8628732fe4ae4" + +ENV FETCH_DEPS="ca-certificates wget dirmngr gnupg2" + +RUN set -xe && \ + apt-get update && apt-get install -y --no-install-recommends ${FETCH_DEPS} && \ + mkdir -p ${PHP_BASE_DIR} && cd ${PHP_BASE_DIR} && \ + wget -O php.tar.xz ${PHP_URL} && \ + echo "${PHP_SHA256} *php.tar.xz" | sha256sum -c - && \ + wget -O php.tar.xz.asc "${PHP_ASC_URL}" && \ + export GNUPGHOME="$(mktemp -d)" && \ + for key in ${GPG_KEYS}; do gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; done && \ + gpg --batch --verify php.tar.xz.asc php.tar.xz && \ + rm -Rf ${GNUPGHOME} && \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false ${FETCH_DEPS} + +ENV BUILD_DEPS="build-essential file libpcre3-dev dpkg-dev libcurl4-openssl-dev libedit-dev libsqlite3-dev libssl1.0-dev libxml2-dev zlib1g-dev" + +RUN set -xe && \ + apt-get update && apt-get install -y --no-install-recommends ${BUILD_DEPS} && \ + export CFLAGS="${PHP_CFLAGS}" CPPFLAGS="${PHP_CPPFLAGS}" LDFLAGS="${PHP_LDFLAGS}" && \ + arch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" && multiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)" && \ + if [ ! -d /usr/include/curl ]; \ + then ln -sT "/usr/include/$multiarch/curl" /usr/local/include/curl; \ + fi && \ + mkdir -p ${PHP_SRC_DIR} && cd ${PHP_SRC_DIR} && \ + tar -xJf ${PHP_BASE_DIR}/php.tar.xz -C . --strip-components=1 && \ + ./configure \ + --prefix=/usr --build="$arch" \ + --with-libdir="lib/$multiarch" \ + --with-pcre-regex=/usr \ + --disable-cgi --disable-fpm \ + --enable-embed --enable-ftp --enable-mbstring \ + --with-curl --with-libedit --with-openssl --with-zlib \ + && \ + make -j "$(nproc)" && \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false ${BUILD_DEPS} + +ENV RUNTIME_DEPS="build-essential git golang curl libedit2 libssl1.0 libxml2" +ENV SOURCE_REPO="github.com/deuill/go-php" + +RUN set -xe && \ + apt-get update && apt-get install -y --no-install-recommends ${RUNTIME_DEPS} && \ + cd ${PHP_SRC_DIR} && make -j "$(nproc)" PHP_SAPI=embed install-sapi install-headers && \ + cd / && rm -Rf ${PHP_BASE_DIR} ${PHP_SRC_DIR} + +ENTRYPOINT ["/bin/sh", "-c"] diff --git a/Dockerfile.php7 b/Dockerfile.php7 new file mode 100644 index 0000000..efd4fb2 --- /dev/null +++ b/Dockerfile.php7 @@ -0,0 +1,60 @@ +FROM debian:stable-slim + +ENV PHP_VERSION="7.1.10" +ENV PHP_URL="https://secure.php.net/get/php-${PHP_VERSION}.tar.xz/from/this/mirror" PHP_ASC_URL="https://secure.php.net/get/php-${PHP_VERSION}.tar.xz.asc/from/this/mirror" + +ENV PHP_BASE_DIR="/tmp/php" +ENV PHP_SRC_DIR="${PHP_BASE_DIR}/src" + +ENV PHP_LDFLAGS="-Wl,-O1 -Wl,--hash-style=both -pie" +ENV PHP_CFLAGS="-fstack-protector-strong -fpic -fpie -O2" +ENV PHP_CPPFLAGS="${PHP_CFLAGS}" + +ENV GPG_KEYS="A917B1ECDA84AEC2B568FED6F50ABC807BD5DCD0 528995BFEDFBA7191D46839EF9BA0ADA31CBD89E" +ENV PHP_SHA256="2b8efa771a2ead0bb3ae67b530ca505b5b286adc873cca9ce97a6e1d6815c50b" + +ENV FETCH_DEPS="ca-certificates wget dirmngr gnupg2" + +RUN set -xe && \ + apt-get update && apt-get install -y --no-install-recommends ${FETCH_DEPS} && \ + mkdir -p ${PHP_BASE_DIR} && cd ${PHP_BASE_DIR} && \ + wget -O php.tar.xz ${PHP_URL} && \ + echo "${PHP_SHA256} *php.tar.xz" | sha256sum -c - && \ + wget -O php.tar.xz.asc "${PHP_ASC_URL}" && \ + export GNUPGHOME="$(mktemp -d)" && \ + for key in ${GPG_KEYS}; do gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; done && \ + gpg --batch --verify php.tar.xz.asc php.tar.xz && \ + rm -Rf ${GNUPGHOME} && \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false ${FETCH_DEPS} + +ENV BUILD_DEPS="build-essential file libpcre3-dev dpkg-dev libcurl4-openssl-dev libedit-dev libsqlite3-dev libssl-dev libxml2-dev zlib1g-dev" + +RUN set -xe && \ + apt-get update && apt-get install -y --no-install-recommends ${BUILD_DEPS} && \ + export CFLAGS="${PHP_CFLAGS}" CPPFLAGS="${PHP_CPPFLAGS}" LDFLAGS="${PHP_LDFLAGS}" && \ + arch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)" && multiarch="$(dpkg-architecture --query DEB_BUILD_MULTIARCH)" && \ + if [ ! -d /usr/include/curl ]; \ + then ln -sT "/usr/include/$multiarch/curl" /usr/local/include/curl; \ + fi && \ + mkdir -p ${PHP_SRC_DIR} && cd ${PHP_SRC_DIR} && \ + tar -xJf ${PHP_BASE_DIR}/php.tar.xz -C . --strip-components=1 && \ + ./configure \ + --prefix=/usr --build="$arch" \ + --with-libdir="lib/$multiarch" \ + --with-pcre-regex=/usr \ + --disable-cgi --disable-fpm \ + --enable-embed --enable-ftp --enable-mbstring \ + --with-curl --with-libedit --with-openssl --with-zlib \ + && \ + make -j "$(nproc)" && \ + apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false ${BUILD_DEPS} + +ENV RUNTIME_DEPS="build-essential git golang curl libedit2 libssl1.1 libxml2" +ENV SOURCE_REPO="github.com/deuill/go-php" + +RUN set -xe && \ + apt-get update && apt-get install -y --no-install-recommends ${RUNTIME_DEPS} && \ + cd ${PHP_SRC_DIR} && make -j "$(nproc)" PHP_SAPI=embed install-sapi install-headers && \ + cd / && rm -Rf ${PHP_BASE_DIR} ${PHP_SRC_DIR} + +ENTRYPOINT ["/bin/sh", "-c"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e4bd358 --- /dev/null +++ b/Makefile @@ -0,0 +1,147 @@ +# Package options. +NAME := go-php +DESCRIPTION := PHP bindings for the Go programming language +IMPORT_PATH := github.com/deuill/$(NAME) +VERSION := $(shell git describe --tags --always --dirty="-dev") +DATE := $(shell date '+%Y-%m-%d-%H%M UTC') + +# Build options. +BUILD_OPTIONS := -ldflags='-X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"' +PACKAGE_FORMAT := tar.xz +PHP_VERSION := php7 +GO := go + +# Install options. +PREFIX := /usr + +# Default Makefile options. +VERBOSE := + +## Default action. Build binary distribution. +all: $(NAME) + +$(NAME): .build/env/GOPATH/.ok + @echo "Building '$(NAME)'..." + $Q $(GO) install $(if $(VERBOSE),-v) $(BUILD_OPTIONS) $(IMPORT_PATH) + +## Print internal package list. +list: .build/env/GOPATH/.ok + @echo $(PACKAGES) + +## Install binary distribution to directory, accepts DESTDIR argument. +install: $(NAME) + @echo "Installing '$(NAME)'..." + $Q mkdir -p $(DESTDIR)/etc/$(NAME) + $Q cp -a dist/conf/. $(DESTDIR)/etc/$(NAME) + $Q install -Dm 0755 .build/env/GOPATH/bin/$(NAME) $(DESTDIR)$(PREFIX)/bin/$(NAME) + +## Run test for all local packages or specified PACKAGE. +test: .build/env/GOPATH/.ok + @echo "Running tests for '$(NAME)'..." + $Q $(GO) test -race $(if $(VERBOSE),-v) -tags $(PHP_VERSION) $(if $(PACKAGE),$(PACKAGE),$(PACKAGES)) + @echo "Running 'vet' for '$(NAME)'..." + $Q $(GO) vet $(if $(VERBOSE),-v) -tags $(PHP_VERSION) $(if $(PACKAGE),$(PACKAGE),$(PACKAGES)) + +## Create test coverage report for all local packages or specified PACKAGE. +cover: .build/env/GOPATH/.ok + @echo "Creating code coverage report for '$(NAME)'..." + $Q rm -Rf .build/tmp && mkdir -p .build/tmp + $Q for pkg in $(if $(PACKAGE),$(PACKAGE),$(PACKAGES)); do \ + name=`echo $$pkg.cover | tr '/' '.'`; \ + imports=`go list -f '{{ join .Imports " " }}' $$pkg`; \ + coverpkg=`echo "$$imports $(PACKAGES)" | tr ' ' '\n' | sort | uniq -d | tr '\n' ','`; \ + $(GO) test $(if $(VERBOSE),-v) -tags $(PHP_VERSION) -coverpkg $$coverpkg$$pkg -coverprofile .build/tmp/$$name $$pkg; done + $Q awk "$$COVERAGE_MERGE" .build/tmp/*.cover > .build/tmp/cover.merged + $Q $(GO) tool cover -html .build/tmp/cover.merged -o .build/tmp/coverage.html + @echo "Coverage report written to '.build/tmp/coverage.html'" + @echo "Total coverage for '$(NAME)':" + $Q $(GO) tool cover -func .build/tmp/cover.merged + +## Package binary distribution to file, accepts PACKAGE_FORMAT argument. +package: clean $(NAME)_$(VERSION).$(PACKAGE_FORMAT) + +## Remove temporary files and packages required for build. +clean: + @echo "Cleaning '$(NAME)'..." + $Q $(GO) clean + $Q rm -Rf .build + +## Show usage information for this Makefile. +help: + @printf "$(BOLD)$(DESCRIPTION)$(RESET)\n\n" + @printf "This Makefile contains tasks for processing auxiliary actions, such as\n" + @printf "building binaries, packages, or running tests against the test suite.\n\n" + @printf "$(UNDERLINE)Available Tasks$(RESET)\n\n" + @awk -F \ + ':|##' '/^##/ {c=$$2; getline; printf "$(BLUE)%10s$(RESET) %s\n", $$1, c}' \ + $(MAKEFILE_LIST) + @printf "\n" + +.PHONY: $(NAME) all install package test cover clean + +.DEFAULT: + $Q $(MAKE) -s -f $(MAKEFILE) help + +docker-image: + $Q docker build -t "$(NAME):$(PHP_VERSION)" -f Dockerfile.$(PHP_VERSION) . + +docker-test: docker-image + $Q docker run --rm \ + -e GOPATH="/tmp/go" \ + -v "$(CURDIR):/tmp/go/src/$(IMPORT_PATH)" $(NAME):$(PHP_VERSION) \ + "make -C /tmp/go/src/$(IMPORT_PATH) test VERBOSE=$(VERBOSE) PHP_VERSION=$(PHP_VERSION)" + +$(NAME)_$(VERSION).tar.xz: .build/dist/.ok + @echo "Building 'tar' package for '$(NAME)'..." + $Q fakeroot -- tar -cJf $(NAME)_$(VERSION).tar.xz -C .build/dist . + +$(NAME)_$(VERSION).deb: .build/dist/.ok + @echo "Building 'deb' package for '$(NAME)'..." + $Q fakeroot -- fpm -f -s dir -t deb \ + -n $(NAME) -v $(VERSION) -p $(NAME)_$(VERSION).deb \ + -C .build/dist + +.build/dist/.ok: + $Q mkdir -p .build/dist && touch $@ + $Q $(MAKE) -s -f $(MAKEFILE) DESTDIR=".build/dist" install + +.build/env/GOPATH/.ok: + $Q mkdir -p "$(dir .build/env/GOPATH/src/$(IMPORT_PATH))" && touch $@ + $Q ln -s ../../../../../.. ".build/env/GOPATH/src/$(IMPORT_PATH)" + +MAKEFILE := $(lastword $(MAKEFILE_LIST)) +Q := $(if $(VERBOSE),,@) + +PACKAGES = $(shell ( \ + cd $(CURDIR)/.build/env/GOPATH/src/$(IMPORT_PATH) && \ + GOPATH=$(CURDIR)/.build/env/GOPATH go list ./... | grep -v "vendor" \ +)) + +export GOPATH := $(CURDIR)/.build/env/GOPATH + +BOLD = \033[1m +UNDERLINE = \033[4m +BLUE = \033[36m +RESET = \033[0m + +define COVERAGE_MERGE +/^mode: (set|count|atomic)/ { + if ($$2 == "set") mode = "set" + next +} +/^mode: / { + printf "Unknown mode '%s' in %s, line %d", $$2, FILENAME, FNR | "cat >&2" + exit 1 +} +{ + val = $$NF; $$NF = "" + blocks[$$0] += val +} +END { + printf "mode: %s\n", (mode == "set") ? "set" : "count" + for (b in blocks) { + printf "%s%d\n", b, (mode == "set" && blocks[b] > 1) ? 1 : blocks[b] + } +} +endef +export COVERAGE_MERGE