├── .dockerignore ├── .github └── workflows │ └── main.yml ├── .gitignore ├── .hadolint.yaml ├── README.md ├── app └── index.php ├── bins └── xdebug-mode ├── conf ├── nginx │ ├── conf.d │ │ ├── compression.conf │ │ └── vhost.conf │ └── nginx.conf └── supervisord.conf ├── docker-compose.yml ├── entrypoint ├── entrypoint.sh └── scripts │ ├── apply_environments.sh │ ├── config_replace.sh │ └── docker_install.sh ├── generator ├── Cargo.lock ├── Cargo.toml └── src │ ├── dockerfiles.rs │ ├── generate.rs │ ├── main.rs │ ├── structs.rs │ └── template_parser.rs ├── php-dev-8.dockerfile ├── php ├── opcache-jit.ini ├── pcov.ini ├── profiler.php ├── xdebug.ini └── xhprof.ini ├── settings.toml ├── templates ├── dependencies.alpine.dockerfile ├── dependencies.debian.dockerfile ├── docker.partial.dockerfile ├── nginx.partial.dockerfile └── template.dockerfile └── user ├── .vimrc └── bashconfig.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | .git/ 2 | .idea/ 3 | php-dev-8.dockerfile 4 | docker-compose.yml 5 | app/ 6 | templates/ 7 | generator/ 8 | src/ 9 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | compile: 6 | runs-on: ubuntu-20.04 7 | steps: 8 | - name: checkout 9 | uses: actions/checkout@v1 10 | - uses: actions-rs/toolchain@v1 11 | with: 12 | toolchain: stable 13 | - uses: actions/cache@v2 14 | with: 15 | path: | 16 | ~/.cargo/registry 17 | ~/.cargo/git 18 | generator/target 19 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 20 | - run: | 21 | # enter generator directory 22 | cd generator 23 | # build rust application 24 | cargo build --release 25 | - name: upload artifact 26 | uses: actions/upload-artifact@master 27 | with: 28 | name: generator 29 | path: generator/target/release/generator 30 | retention-days: 1 31 | generate: 32 | name: Generate and lint Dockerfiles 33 | runs-on: ubuntu-20.04 34 | needs: [compile] 35 | strategy: 36 | matrix: 37 | cli: [ dev, prod ] 38 | type: [ alpine, debian, cli ] 39 | steps: 40 | - name: checkout 41 | uses: actions/checkout@v1 42 | - uses: actions/download-artifact@master 43 | with: 44 | name: generator 45 | path: generator 46 | - name: generate dockerfiles 47 | run: | 48 | chmod +x generator/generator 49 | generator/generator ${{ matrix.cli }} --type=${{ matrix.type }} 50 | - name: lint dockerfiles 51 | uses: brpaz/hadolint-action@master 52 | with: 53 | dockerfile: "Dockerfile" 54 | - name: upload artifact 55 | uses: actions/upload-artifact@master 56 | with: 57 | name: Dockerfile-${{ matrix.cli }}-${{ matrix.type }} 58 | path: Dockerfile 59 | retention-days: 1 60 | build-bc: 61 | runs-on: ubuntu-20.04 62 | needs: [ generate ] 63 | if: github.ref == 'refs/heads/main' 64 | steps: 65 | - name: checkout 66 | uses: actions/checkout@v2 67 | - uses: actions/download-artifact@master 68 | with: 69 | name: Dockerfile-dev-alpine 70 | path: . 71 | - name: update php-dev-8.dockerfile 72 | run: cp Dockerfile php-dev-8.dockerfile 73 | - uses: stefanzweifel/git-auto-commit-action@v4 74 | with: 75 | commit_message: "GitHub-Action: Update php 8.0 alpine dockerfile" 76 | - name: Build image 77 | # if: steps.auto-commit-action.outputs.changes_detected == 'true' 78 | run: docker build . --file php-dev-8.dockerfile --tag php8-nginx-xdebug 79 | - name: Log into registry 80 | # if: steps.auto-commit-action.outputs.changes_detected == 'true' 81 | run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login docker.pkg.github.com -u ${{ github.actor }} --password-stdin 82 | - name: Push image 83 | # if: steps.auto-commit-action.outputs.changes_detected == 'true' 84 | run: | 85 | IMAGE_NAME=php8-nginx-xdebug 86 | IMAGE_ID=docker.pkg.github.com/${{ github.repository }}/$IMAGE_NAME 87 | IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') 88 | docker tag $IMAGE_NAME $IMAGE_ID:latest 89 | docker push $IMAGE_ID:latest 90 | build-docker: 91 | runs-on: ubuntu-20.04 92 | needs: [ generate ] 93 | if: github.ref == 'refs/heads/main' 94 | strategy: 95 | matrix: 96 | cli: [ dev, prod ] 97 | type: [ alpine, debian, cli ] 98 | steps: 99 | - name: checkout 100 | uses: actions/checkout@v2 101 | - uses: actions/download-artifact@master 102 | with: 103 | name: Dockerfile-${{ matrix.cli }}-${{ matrix.type }} 104 | path: . 105 | - name: Build and Push Dockerfile ${{ matrix.cli }} ${{ matrix.type }} 106 | uses: docker/build-push-action@v1.1.0 107 | env: 108 | DEV_ENV: ${{ fromJSON('["", "-dev"]')[matrix.cli == 'dev'] }} 109 | VARIANT_ENV: ${{ fromJSON('["-nginx", ""]')[matrix.type == 'cli'] }} 110 | with: 111 | username: ${{ secrets.DOCKER_USERNAME }} 112 | password: ${{ secrets.DOCKER_PASSWORD }} 113 | repository: chrisb9/php8 114 | tags: ${{ matrix.type }}${{ env.VARIANT_ENV }}${{ env.DEV_ENV }} 115 | path: . 116 | - name: push README to Dockerhub 117 | uses: christian-korneck/update-container-description-action@v1 118 | env: 119 | DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} 120 | DOCKER_PASS: ${{ secrets.DOCKER_PASSWORD }} 121 | with: 122 | destination_container_repo: chrisb9/php8 123 | provider: dockerhub 124 | readme_file: 'README.md' 125 | sync-readme: 126 | runs-on: ubuntu-20.04 127 | if: github.ref == 'refs/heads/main' 128 | steps: 129 | - name: checkout 130 | uses: actions/checkout@v2 131 | - name: push README to Dockerhub 132 | uses: christian-korneck/update-container-description-action@v1 133 | env: 134 | DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} 135 | DOCKER_PASS: ${{ secrets.DOCKER_PASSWORD }} 136 | with: 137 | destination_container_repo: chrisb9/php8 138 | provider: dockerhub 139 | readme_file: 'README.md' -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.log 3 | *.pid 4 | generator/target 5 | Dockerfile -------------------------------------------------------------------------------- /.hadolint.yaml: -------------------------------------------------------------------------------- 1 | ignored: 2 | - DL3008 3 | - DL3003 4 | - DL4006 5 | - SC2086 6 | - DL3002 7 | - DL3018 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![CI](https://github.com/ChrisB9/php8-xdebug/workflows/CI/badge.svg?branch=main) 2 | 3 | # PHP 8.0 for development and production 4 | 5 | > **Note**: 6 | > This image is transitioning from a simple dev image to a more configurable and extensible image 7 | > Therefore it is currently being pushed into two different docker repositories: 8 | > (old:) [https://hub.docker.com/r/chrisb9/php8-nginx-xdebug](https://hub.docker.com/r/chrisb9/php8-nginx-xdebug) 9 | > (new:) [https://hub.docker.com/r/chrisb9/php8](https://hub.docker.com/r/chrisb9/php8) 10 | 11 | ## The Images: 12 | 13 | There are three image configurations in two different types: 14 | 15 | | Image Type | Image Variant | With nginx | 16 | |:----------:|:-------------:|:----------:| 17 | | Alpine | dev and prod | yes | 18 | | Debian | dev and prod | yes | 19 | | CLI | dev and prod | no | 20 | 21 | ### current features 22 | 23 | - **nginx based image:** nginx with brotli and http2 enabled 24 | - **dev image:** php 8.0 ✨ (with xdebug, opcache, ffi, and jit enabled by default) 25 | - **prod image:** php 8.0 ✨ (with opcache, and jit enabled by default) 26 | - **dev image:** xdebug 3.0 (set to profile, debug and develop-mode) 27 | - **dev image:** pcov 28 | - composer v2.0 (composer 1.0 has been removed) 29 | - bash (with auto-completion extension and colored) 30 | - webp and image-optimizers 31 | - mariadb support 32 | - **cli image**: no fpm and no nginx preinstalled - this is your smaller variant, not based on alpine (yet) 33 | 34 | planned: 35 | - mongodb support 36 | - apache-based image 37 | - easier extension installation 38 | - tideways profiler with perf-tools enabled 39 | 40 | This repository does only provide Dockerfiles for php 8.0 and upwards. 41 | If there is enough traction, I might add PHP 7.4 too (or feel free to add it) 42 | 43 | ### docker-socket 44 | 45 | If docker socket has been mounted as a volume into the container, 46 | then each startup checks the availability of the docker command and if not available installs it. 47 | > Note: This is currently only available in alpine images: WIP 48 | 49 | ## xdebug settings: 50 | 51 | Some xdebug settings have been preconfigured, such as: 52 | - `xdebug.mode=profile,develop,coverage` 53 | - `xdebug.client_port=9003` 54 | - `xdebug.discover_client_host=1` 55 | - `xdebug.idekey=PHPSTORM` 56 | 57 | Through the environment-variable `XDEBUG_HOST` the client_host can be changed on login 58 | 59 | ### xdebug tools: 60 | - `xdebug-enable` enabled xdebug and restarts php 61 | - `xdebug-disable` disables xdebug and restarts php 62 | 63 | ## testing this dockerfile: 64 | 65 | just run `git clone && docker-compose up -d`
66 | then open up your browser and go to this container. 67 | 68 | in the app-folder are two files index.php and Test.php. 69 | They are meant as a playground to test the newest features of php 8.0 70 | 71 | ## Contributing 72 | 73 | todo... 74 | -------------------------------------------------------------------------------- /app/index.php: -------------------------------------------------------------------------------- 1 | > /tmp/xdebug.ini 13 | $SUDO mv /tmp/xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini 14 | test ! -z "$IS_CLI" && $SUDO supervisorctl -c /opt/docker/supervisord.conf restart php-fpm:php-fpm 15 | -------------------------------------------------------------------------------- /conf/nginx/conf.d/compression.conf: -------------------------------------------------------------------------------- 1 | gzip on; 2 | gzip_vary on; 3 | gzip_proxied any; 4 | gzip_comp_level 6; 5 | gzip_types text/plain text/css text/xml application/json application/javascript application/xml+rss application/atom+xml image/svg+xml; 6 | 7 | brotli on; 8 | brotli_comp_level 6; 9 | brotli_static on; 10 | brotli_types application/atom+xml application/javascript application/json application/rss+xml 11 | application/vnd.ms-fontobject application/x-font-opentype application/x-font-truetype 12 | application/x-font-ttf application/x-javascript application/xhtml+xml application/xml 13 | font/eot font/opentype font/otf font/truetype image/svg+xml image/vnd.microsoft.icon 14 | image/x-icon image/x-win-bitmap text/css text/javascript text/plain text/xml; -------------------------------------------------------------------------------- /conf/nginx/conf.d/vhost.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | server_name ${WEB_ALIAS_DOMAIN}; 4 | 5 | root ${WEB_DOCUMENT_ROOT}; 6 | index ${WEB_DOCUMENT_INDEX}; 7 | 8 | client_max_body_size ${NGINX_CLIENT_MAX_BODY}; 9 | 10 | location / { 11 | try_files $uri $uri/ /${WEB_DOCUMENT_INDEX}?$query_string; 12 | } 13 | 14 | location ~ \.php { 15 | fastcgi_index index.php; 16 | fastcgi_pass localhost:9000; 17 | 18 | include /etc/nginx/fastcgi_params; 19 | fastcgi_split_path_info ^(.+\.php)(/.+)$; 20 | fastcgi_param PATH_INFO $fastcgi_path_info; 21 | fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; 22 | fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 23 | fastcgi_read_timeout ${WEB_PHP_TIMEOUT}; 24 | } 25 | 26 | 27 | location ~* ${WEB_NO_CACHE_PATTERN} { 28 | expires off; 29 | add_header Cache-Control private; 30 | 31 | try_files $uri $uri/ /${WEB_DOCUMENT_INDEX}?$query_string; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /conf/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | user nginx; 2 | worker_processes 1; 3 | 4 | include /etc/nginx/modules-enabled/*.conf; 5 | 6 | error_log /var/log/nginx/error.log warn; 7 | pid /var/run/nginx.pid; 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | http { 14 | include /etc/nginx/mime.types; 15 | default_type application/octet-stream; 16 | 17 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 18 | '$status $body_bytes_sent "$http_referer" ' 19 | '"$http_user_agent" "$http_x_forwarded_for"'; 20 | 21 | access_log /var/log/nginx/access.log main; 22 | 23 | sendfile on; 24 | #tcp_nopush on; 25 | 26 | keepalive_timeout 65; 27 | 28 | include /opt/docker/nginx/conf.d/*.conf; 29 | } 30 | -------------------------------------------------------------------------------- /conf/supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | logfile=/var/log/supervisord/supervisord.log 3 | childlogdir=/var/log/supervisord/ 4 | user=root 5 | pidfile=/run/supervisord.pid 6 | logfile_maxbytes=50MB 7 | logfile_backups=10 8 | loglevel=info 9 | nodaemon=true 10 | 11 | [unix_http_server] 12 | file=/run/supervisord.sock ; the path to the socket file 13 | 14 | [supervisorctl] 15 | serverurl=unix:///run/supervisord.sock 16 | 17 | [rpcinterface:supervisor] 18 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 19 | 20 | [program:php-fpm] 21 | command=php-fpm --nodaemonize 22 | startsecs = 0 23 | autostart = true 24 | autorestart = true 25 | stdout_logfile=/dev/stdout 26 | stdout_logfile_maxbytes=0 27 | stderr_logfile=/dev/stderr 28 | stderr_logfile_maxbytes=0 29 | 30 | [program:nginx] 31 | command=nginx -c /opt/docker/nginx/nginx.conf -g "daemon off;" 32 | startsecs = 0 33 | autostart = true 34 | autorestart = true 35 | stdout_logfile=/dev/stdout 36 | stdout_logfile_maxbytes=0 37 | stderr_logfile=/dev/stderr 38 | stderr_logfile_maxbytes=0 39 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.5' 2 | 3 | services: 4 | php: 5 | build: 6 | dockerfile: Dockerfile 7 | context: . 8 | volumes: 9 | - ./app:/app 10 | environment: 11 | - VIRTUAL_HOST=php8.local.cben.dev 12 | - php.memory_limit=-1 13 | 14 | lint: 15 | image: hadolint/hadolint 16 | volumes: 17 | - ./.hadolint.yaml:/root/.config/.hadolint.yaml:ro 18 | - ./Dockerfile:/Dockerfile:ro 19 | command: "hadolint /Dockerfile" 20 | 21 | networks: 22 | default: 23 | external: 24 | name: global 25 | -------------------------------------------------------------------------------- /entrypoint/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o pipefail 4 | set -o errtrace 5 | 6 | for filename in /entrypoint.d/*.sh; do 7 | [ -e "$filename" ] || continue; 8 | echo "Running now: $filename" 9 | bash "$filename" 10 | done; 11 | 12 | exec /usr/bin/supervisord -nc /opt/docker/supervisord.conf 13 | -------------------------------------------------------------------------------- /entrypoint/scripts/apply_environments.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | function listEnvs() { 4 | env | grep "^${1}" | cut -d= -f1 5 | } 6 | 7 | function getEnvVar() { 8 | awk "BEGIN {print ENVIRON[\"$1\"]}" 9 | } 10 | 11 | for ENV_VAR in $(listEnvs "php\."); do 12 | env_key=${ENV_VAR#php.} 13 | env_val=$(getEnvVar "$ENV_VAR") 14 | 15 | echo "$env_key = ${env_val}" >> /usr/local/etc/php/conf.d/x.override.php.ini 16 | done 17 | 18 | if [[ -n "${XDEBUG_HOST}" ]]; then 19 | cat /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini | sed "s|\#\ xdebug\.client\_host\ \=|xdebug\.client\_host=${XDEBUG_HOST}|g" >> /tmp/xdebug.ini 20 | mv /tmp/xdebug.ini /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini 21 | fi 22 | 23 | test -z "$PHP_MEMORY_LIMIT" && echo "memory_limit = ${PHP_MEMORY_LIMIT}" >> /usr/local/etc/php/conf.d/x.override.php.ini 24 | test -z "$PHP_DISPLAY_ERRORS" && echo "memory_limit = ${PHP_DISPLAY_ERRORS}" >> /usr/local/etc/php/conf.d/x.override.php.ini -------------------------------------------------------------------------------- /entrypoint/scripts/config_replace.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ambr --no-interactive '${WEB_DOCUMENT_ROOT}' "$WEB_DOCUMENT_ROOT" /opt/docker/nginx/ 4 | ambr --no-interactive '${WEB_DOCUMENT_INDEX}' "$WEB_DOCUMENT_INDEX" /opt/docker/nginx/ 5 | ambr --no-interactive '${WEB_ALIAS_DOMAIN}' "$WEB_ALIAS_DOMAIN" /opt/docker/nginx/ 6 | ambr --no-interactive '${WEB_PHP_TIMEOUT}' "$WEB_PHP_TIMEOUT" /opt/docker/nginx/ 7 | ambr --no-interactive '${WEB_PHP_SOCKET}' "$WEB_PHP_SOCKET" /opt/docker/nginx/ 8 | ambr --no-interactive '${NGINX_CLIENT_MAX_BODY}' "$NGINX_CLIENT_MAX_BODY" /opt/docker/nginx/ 9 | ambr --no-interactive '${WEB_NO_CACHE_PATTERN}' "$WEB_NO_CACHE_PATTERN" /opt/docker/nginx/ -------------------------------------------------------------------------------- /entrypoint/scripts/docker_install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -e /var/run/docker.sock ] && [ -n "$IS_ALPINE" ]; then 4 | apk add docker 5 | fi 6 | if [ -e /var/run/docker.sock ] && [ -z "$IS_ALPINE" ]; then 7 | apt update && apt install docker 8 | fi 9 | -------------------------------------------------------------------------------- /generator/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "addr2line" 5 | version = "0.14.0" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" 8 | dependencies = [ 9 | "gimli", 10 | ] 11 | 12 | [[package]] 13 | name = "adler" 14 | version = "0.2.3" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" 17 | 18 | [[package]] 19 | name = "aho-corasick" 20 | version = "0.7.15" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" 23 | dependencies = [ 24 | "memchr", 25 | ] 26 | 27 | [[package]] 28 | name = "arrayvec" 29 | version = "0.5.2" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" 32 | 33 | [[package]] 34 | name = "autocfg" 35 | version = "1.0.1" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 38 | 39 | [[package]] 40 | name = "backtrace" 41 | version = "0.3.54" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "2baad346b2d4e94a24347adeee9c7a93f412ee94b9cc26e5b59dea23848e9f28" 44 | dependencies = [ 45 | "addr2line", 46 | "cfg-if 1.0.0", 47 | "libc", 48 | "miniz_oxide", 49 | "object", 50 | "rustc-demangle", 51 | ] 52 | 53 | [[package]] 54 | name = "bitflags" 55 | version = "1.2.1" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 58 | 59 | [[package]] 60 | name = "cfg-if" 61 | version = "0.1.10" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 64 | 65 | [[package]] 66 | name = "cfg-if" 67 | version = "1.0.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 70 | 71 | [[package]] 72 | name = "config" 73 | version = "0.10.1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" 76 | dependencies = [ 77 | "lazy_static", 78 | "nom", 79 | "rust-ini", 80 | "serde 1.0.117", 81 | "serde-hjson", 82 | "serde_json", 83 | "toml", 84 | "yaml-rust", 85 | ] 86 | 87 | [[package]] 88 | name = "failure" 89 | version = "0.1.8" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" 92 | dependencies = [ 93 | "backtrace", 94 | "failure_derive", 95 | ] 96 | 97 | [[package]] 98 | name = "failure_derive" 99 | version = "0.1.8" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" 102 | dependencies = [ 103 | "proc-macro2", 104 | "quote", 105 | "syn", 106 | "synstructure", 107 | ] 108 | 109 | [[package]] 110 | name = "generator" 111 | version = "0.1.0" 112 | dependencies = [ 113 | "config", 114 | "failure", 115 | "failure_derive", 116 | "seahorse", 117 | "serde 1.0.117", 118 | "serde_derive", 119 | "terminal_color_builder", 120 | "tinytemplate", 121 | ] 122 | 123 | [[package]] 124 | name = "gimli" 125 | version = "0.23.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" 128 | 129 | [[package]] 130 | name = "itoa" 131 | version = "0.4.6" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" 134 | 135 | [[package]] 136 | name = "lazy_static" 137 | version = "1.4.0" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 140 | 141 | [[package]] 142 | name = "lexical-core" 143 | version = "0.7.4" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616" 146 | dependencies = [ 147 | "arrayvec", 148 | "bitflags", 149 | "cfg-if 0.1.10", 150 | "ryu", 151 | "static_assertions", 152 | ] 153 | 154 | [[package]] 155 | name = "libc" 156 | version = "0.2.80" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" 159 | 160 | [[package]] 161 | name = "linked-hash-map" 162 | version = "0.3.0" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" 165 | dependencies = [ 166 | "serde 0.8.23", 167 | "serde_test", 168 | ] 169 | 170 | [[package]] 171 | name = "linked-hash-map" 172 | version = "0.5.3" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" 175 | 176 | [[package]] 177 | name = "memchr" 178 | version = "2.3.4" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" 181 | 182 | [[package]] 183 | name = "miniz_oxide" 184 | version = "0.4.3" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" 187 | dependencies = [ 188 | "adler", 189 | "autocfg", 190 | ] 191 | 192 | [[package]] 193 | name = "nom" 194 | version = "5.1.2" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" 197 | dependencies = [ 198 | "lexical-core", 199 | "memchr", 200 | "version_check", 201 | ] 202 | 203 | [[package]] 204 | name = "num-traits" 205 | version = "0.1.43" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" 208 | dependencies = [ 209 | "num-traits 0.2.14", 210 | ] 211 | 212 | [[package]] 213 | name = "num-traits" 214 | version = "0.2.14" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 217 | dependencies = [ 218 | "autocfg", 219 | ] 220 | 221 | [[package]] 222 | name = "object" 223 | version = "0.22.0" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" 226 | 227 | [[package]] 228 | name = "proc-macro2" 229 | version = "1.0.24" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 232 | dependencies = [ 233 | "unicode-xid", 234 | ] 235 | 236 | [[package]] 237 | name = "quote" 238 | version = "1.0.7" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" 241 | dependencies = [ 242 | "proc-macro2", 243 | ] 244 | 245 | [[package]] 246 | name = "regex" 247 | version = "1.4.2" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" 250 | dependencies = [ 251 | "aho-corasick", 252 | "memchr", 253 | "regex-syntax", 254 | "thread_local", 255 | ] 256 | 257 | [[package]] 258 | name = "regex-syntax" 259 | version = "0.6.21" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" 262 | 263 | [[package]] 264 | name = "rust-ini" 265 | version = "0.13.0" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" 268 | 269 | [[package]] 270 | name = "rustc-demangle" 271 | version = "0.1.18" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" 274 | 275 | [[package]] 276 | name = "ryu" 277 | version = "1.0.5" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 280 | 281 | [[package]] 282 | name = "seahorse" 283 | version = "1.1.1" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "ce7d9440e2865cce0db733bdc530591b37d37a2d32badace34a1fc9ba5686d58" 286 | 287 | [[package]] 288 | name = "serde" 289 | version = "0.8.23" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" 292 | 293 | [[package]] 294 | name = "serde" 295 | version = "1.0.117" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" 298 | 299 | [[package]] 300 | name = "serde-hjson" 301 | version = "0.9.1" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8" 304 | dependencies = [ 305 | "lazy_static", 306 | "linked-hash-map 0.3.0", 307 | "num-traits 0.1.43", 308 | "regex", 309 | "serde 0.8.23", 310 | ] 311 | 312 | [[package]] 313 | name = "serde_derive" 314 | version = "1.0.117" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" 317 | dependencies = [ 318 | "proc-macro2", 319 | "quote", 320 | "syn", 321 | ] 322 | 323 | [[package]] 324 | name = "serde_json" 325 | version = "1.0.59" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" 328 | dependencies = [ 329 | "itoa", 330 | "ryu", 331 | "serde 1.0.117", 332 | ] 333 | 334 | [[package]] 335 | name = "serde_test" 336 | version = "0.8.23" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" 339 | dependencies = [ 340 | "serde 0.8.23", 341 | ] 342 | 343 | [[package]] 344 | name = "static_assertions" 345 | version = "1.1.0" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 348 | 349 | [[package]] 350 | name = "syn" 351 | version = "1.0.48" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" 354 | dependencies = [ 355 | "proc-macro2", 356 | "quote", 357 | "unicode-xid", 358 | ] 359 | 360 | [[package]] 361 | name = "synstructure" 362 | version = "0.12.4" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" 365 | dependencies = [ 366 | "proc-macro2", 367 | "quote", 368 | "syn", 369 | "unicode-xid", 370 | ] 371 | 372 | [[package]] 373 | name = "terminal_color_builder" 374 | version = "0.1.1" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "51bc10d4f2e7a2580c9fbeb550ef748c81430cfaffb046f047204bb5a75dbff0" 377 | 378 | [[package]] 379 | name = "thread_local" 380 | version = "1.0.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 383 | dependencies = [ 384 | "lazy_static", 385 | ] 386 | 387 | [[package]] 388 | name = "tinytemplate" 389 | version = "1.1.0" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" 392 | dependencies = [ 393 | "serde 1.0.117", 394 | "serde_json", 395 | ] 396 | 397 | [[package]] 398 | name = "toml" 399 | version = "0.5.7" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" 402 | dependencies = [ 403 | "serde 1.0.117", 404 | ] 405 | 406 | [[package]] 407 | name = "unicode-xid" 408 | version = "0.2.1" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 411 | 412 | [[package]] 413 | name = "version_check" 414 | version = "0.9.2" 415 | source = "registry+https://github.com/rust-lang/crates.io-index" 416 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 417 | 418 | [[package]] 419 | name = "yaml-rust" 420 | version = "0.4.4" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d" 423 | dependencies = [ 424 | "linked-hash-map 0.5.3", 425 | ] 426 | -------------------------------------------------------------------------------- /generator/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generator" 3 | version = "0.1.0" 4 | authors = ["Christian Rodriguez Benthake "] 5 | homepage = "https://cben.dev" 6 | repository = "https://github.com/ChrisB9/php8-xdebug" 7 | license = "MIT" 8 | edition = "2018" 9 | 10 | [dependencies] 11 | tinytemplate = "1.0" 12 | serde = "^1.0" 13 | serde_derive = "^1.0" 14 | failure = "0.1.8" 15 | failure_derive = "0.1.8" 16 | seahorse = "1.1" 17 | terminal_color_builder = "0.1.1" 18 | config = "^0.10" -------------------------------------------------------------------------------- /generator/src/dockerfiles.rs: -------------------------------------------------------------------------------- 1 | use crate::generate::Generate; 2 | use crate::structs::*; 3 | use std::collections::HashMap; 4 | 5 | fn get_from(container_type: &ContainerType) -> String { 6 | String::from(match container_type { 7 | ContainerType::ALPINE => "php:8.0.0-fpm-alpine", 8 | ContainerType::DEBIAN => "php:8.0.0-fpm", 9 | ContainerType::CLI => "php:8.0.0-cli", 10 | }) 11 | } 12 | 13 | fn get_is_alpine(container_type: &ContainerType) -> bool { 14 | *container_type == ContainerType::ALPINE 15 | } 16 | 17 | fn get_is_web(container_type: &ContainerType) -> bool { 18 | *container_type != ContainerType::CLI 19 | } 20 | 21 | impl Generate for ProdDockerfile { 22 | fn new(container_type: Option) -> ProdDockerfile { 23 | let container_type: ContainerType = container_type.unwrap_or(ContainerType::ALPINE); 24 | let from: String = get_from(&container_type); 25 | let use_apk: bool = get_is_alpine(&container_type); 26 | let is_web: bool = get_is_web(&container_type); 27 | ProdDockerfile { 28 | base: Dockerfile { 29 | from, 30 | container_type, 31 | envs: HashMap::new(), 32 | use_apk, 33 | is_web, 34 | }, 35 | is_dev: false, 36 | } 37 | } 38 | } 39 | 40 | impl Generate for DevDockerfile { 41 | fn new(container_type: Option) -> DevDockerfile { 42 | let container_type: ContainerType = container_type.unwrap_or(ContainerType::ALPINE); 43 | let mut envs: HashMap = HashMap::new(); 44 | envs.insert(String::from("XDEBUG_VERSION"), String::from("3.0.0")); 45 | let from: String = get_from(&container_type); 46 | let use_apk: bool = get_is_alpine(&container_type); 47 | let is_web: bool = get_is_web(&container_type); 48 | DevDockerfile { 49 | base: Dockerfile { 50 | from, 51 | container_type, 52 | envs, 53 | use_apk, 54 | is_web, 55 | }, 56 | is_dev: true, 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /generator/src/generate.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use std::fs; 3 | use crate::template_parser::Parsing; 4 | use serde::Serialize; 5 | use std::fs::File; 6 | use std::io::prelude::*; 7 | use crate::structs::ContainerType; 8 | use config::Config; 9 | use std::collections::HashMap; 10 | use serde::export::fmt::Debug; 11 | 12 | pub trait Generate: Serialize + Debug { 13 | fn new(container_type: Option) -> Self; 14 | 15 | fn load_config(&self) -> HashMap { 16 | let mut settings: Config = Config::default(); 17 | settings.merge(config::File::with_name("settings")).unwrap(); 18 | settings.try_into::>().unwrap() 19 | } 20 | 21 | fn generate(&self) -> Result> { 22 | let config = self.load_config(); 23 | let parser = Parsing::new(config); 24 | match parser.render(&self) { 25 | Err(e) => Err(e), 26 | Ok(r) => Ok(r), 27 | } 28 | } 29 | 30 | fn to_file(&self) -> Result<(), failure::Error> { 31 | let config = self.load_config(); 32 | let filename: &str = &config["output_path"]; 33 | if Path::new(filename).exists() { 34 | fs::remove_file(filename)?; 35 | } 36 | let mut file = File::create(filename)?; 37 | let result = self.generate()?; 38 | file.write_all(result.as_bytes())?; 39 | Ok(()) 40 | } 41 | } -------------------------------------------------------------------------------- /generator/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | pub extern crate serde_derive; 3 | pub extern crate tinytemplate; 4 | pub extern crate failure_derive; 5 | 6 | mod dockerfiles; 7 | mod structs; 8 | mod template_parser; 9 | mod generate; 10 | 11 | use structs::*; 12 | use generate::Generate; 13 | use seahorse::{App, Context, Command, Flag, FlagType}; 14 | use std::env; 15 | use std::fmt::Display; 16 | use terminal_color_builder::OutputFormatter as tcb; 17 | use seahorse::error::FlagError; 18 | 19 | pub fn main() { 20 | let args: Vec = env::args().collect(); 21 | let app = App::new(cmd(env!("CARGO_PKG_NAME"))) 22 | .description(cmd("generate php 8.0 dockerfile by template")) 23 | .command(generate_prod()) 24 | .command(generate_test()); 25 | 26 | app.run(args); 27 | } 28 | 29 | fn success(t: T) -> () { 30 | println!("{}", tcb::new().fg().hex("#fff").bg().green().text(t.to_string()).print()); 31 | } 32 | 33 | fn error(t: T) -> String { 34 | format!("{}", tcb::new().fg().hex("#fff").bg().red().text(t.to_string()).print()) 35 | } 36 | 37 | fn cmd(str: &str) -> String { 38 | tcb::new().fg().hex("#6f0").text_str(str).print() 39 | } 40 | 41 | fn parse_container_type(c: &Context) -> ContainerType { 42 | match c.string_flag("type") { 43 | Ok(t) => match &*t { 44 | "alpine" => ContainerType::ALPINE, 45 | "debian" => ContainerType::DEBIAN, 46 | "cli" => ContainerType::CLI, 47 | _ => panic!("{} {} {}", error("undefined container-type"), t, ": available types are debian, alpine, cli") 48 | } 49 | Err(e) => match e { 50 | FlagError::NotFound => ContainerType::ALPINE, 51 | _ => panic!("{} {:?}", error("Flag-Error"), e), 52 | } 53 | } 54 | } 55 | 56 | fn generate_prod_action(c: &Context) { 57 | let container_type = parse_container_type(c); 58 | let dockerfile: ProdDockerfile = Generate::new(Option::from(container_type)); 59 | match dockerfile.to_file() { 60 | Err(e) => panic!(format!("{:?}", e)), 61 | _ => success("Successfully generated file"), 62 | } 63 | } 64 | 65 | fn generate_test_action(c: &Context) { 66 | let container_type = parse_container_type(c); 67 | let dockerfile: DevDockerfile = Generate::new(Option::from(container_type)); 68 | match dockerfile.to_file() { 69 | Err(e) => panic!(format!("{:?}", e)), 70 | _ => success("Successfully generated file"), 71 | } 72 | } 73 | 74 | fn generate_prod() -> Command { 75 | Command::new("prod") 76 | .description(cmd("generate prod-php dockerfile")) 77 | .alias(cmd("p")) 78 | .usage(cmd("cli prod")) 79 | .action(generate_prod_action) 80 | .flag( 81 | Flag::new("type", FlagType::String) 82 | .description(cmd("Build either a debian-based or a alpine-based image (--type=debian or --type=alpine)")) 83 | .alias("t") 84 | ) 85 | } 86 | 87 | fn generate_test() -> Command { 88 | Command::new("dev") 89 | .description(cmd("generate dev-php dockerfile")) 90 | .alias(cmd("d")) 91 | .usage(cmd("cli dev")) 92 | .action(generate_test_action) 93 | .flag( 94 | Flag::new("type", FlagType::String) 95 | .description(cmd("Build either a debian-based or a alpine-based image (--type=debian or --type=alpine)")) 96 | .alias("t") 97 | ) 98 | } 99 | -------------------------------------------------------------------------------- /generator/src/structs.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | #[derive(PartialOrd, PartialEq, Debug, Serialize)] 4 | pub enum ContainerType { 5 | ALPINE, 6 | DEBIAN, 7 | CLI, 8 | } 9 | 10 | #[derive(Debug, Serialize)] 11 | pub struct Dockerfile { 12 | pub from: String, 13 | pub container_type: ContainerType, 14 | pub envs: HashMap, 15 | pub use_apk: bool, 16 | pub is_web: bool, 17 | } 18 | 19 | #[derive(Debug, Serialize)] 20 | pub struct ProdDockerfile { 21 | pub base: Dockerfile, 22 | pub is_dev: bool, 23 | } 24 | 25 | #[derive(Debug, Serialize)] 26 | pub struct DevDockerfile { 27 | pub base: Dockerfile, 28 | pub is_dev: bool, 29 | } -------------------------------------------------------------------------------- /generator/src/template_parser.rs: -------------------------------------------------------------------------------- 1 | use tinytemplate::TinyTemplate; 2 | use std::{fs::{File, read_dir}, io::prelude::*, collections::HashMap, path::Path, io}; 3 | use failure::Fail; 4 | use serde::Serialize; 5 | use serde::export::fmt::Debug; 6 | 7 | #[derive(Fail, Debug)] 8 | #[fail(display = "An error occurred while parsing the template: {}.", _0)] 9 | pub struct TemplatingError(String); 10 | 11 | pub struct Parsing { 12 | config: HashMap 13 | } 14 | 15 | struct TemplateFileCollection { 16 | template_content: HashMap 17 | } 18 | 19 | impl TemplateFileCollection { 20 | pub fn new() -> TemplateFileCollection { 21 | TemplateFileCollection { 22 | template_content: HashMap::new(), 23 | } 24 | } 25 | 26 | fn read_dirs(dir: &str) -> io::Result> { 27 | let path = Path::new(dir); 28 | let mut collection: Vec = vec![]; 29 | if path.is_dir() { 30 | for file in read_dir(path)? { 31 | let file = file?; 32 | if !file.path().is_dir() { 33 | collection.push(file.path().as_os_str().to_str().unwrap().to_string()); 34 | } 35 | } 36 | } 37 | Ok(collection) 38 | } 39 | 40 | pub fn read_for_dir(&mut self, dir: &str) -> io::Result<()> { 41 | let collection = TemplateFileCollection::read_dirs(dir)?; 42 | for file in &collection { 43 | self.add_file_content(file)?; 44 | } 45 | Ok(()) 46 | } 47 | 48 | pub fn read_file(file: &str) -> io::Result { 49 | let mut handle = File::open(file)?; 50 | let mut contents = String::new(); 51 | handle.read_to_string(&mut contents)?; 52 | Ok(contents) 53 | } 54 | 55 | pub fn add_file_content(&mut self, file: &str) -> io::Result<()> { 56 | let contents = TemplateFileCollection::read_file(file).unwrap(); 57 | let filename = Path::new(&file).file_name().unwrap(); 58 | let mut filename = String::from(filename.to_str().unwrap()); 59 | filename = filename.replace(".", "_"); 60 | self.template_content.insert(filename, contents); 61 | Ok(()) 62 | } 63 | } 64 | 65 | impl Parsing { 66 | pub fn new(config: HashMap) -> Parsing { 67 | Parsing { 68 | config, 69 | } 70 | } 71 | 72 | fn get_error(&self, message: &str) -> Box { 73 | Box::new(TemplatingError(String::from(message))) 74 | } 75 | 76 | pub fn render(&self, context: &S) -> Result> where S: Serialize + Debug { 77 | let mut template = TinyTemplate::new(); 78 | let mut collection = TemplateFileCollection::new(); 79 | match collection.read_for_dir(&self.config["template_path"]) { 80 | Ok(_r) => (), 81 | Err(_e) => return Err(self.get_error("Failed parsing template directory")), 82 | }; 83 | for file in &collection.template_content { 84 | match template.add_template(file.0, file.1) { 85 | Ok(_r) => (), 86 | Err(_e) => return Err(self.get_error(&format!("Failed parsing template directory for dockerfile {:?} {:?}", _e, context))), 87 | }; 88 | } 89 | 90 | return match template.render(&self.config["base_template"], &context) { 91 | Err(e) => { 92 | println!("{}", e); 93 | Err(self.get_error("Rendering Template failed")) 94 | }, 95 | Ok(r) => Ok(r), 96 | }; 97 | } 98 | } -------------------------------------------------------------------------------- /php-dev-8.dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:8.0.0-fpm-alpine 2 | 3 | ENV TERM="xterm" \ 4 | LANG="C.UTF-8" \ 5 | LC_ALL="C.UTF-8" 6 | ENV DOCKER_CONF_HOME=/opt/docker/ 7 | ENV APPLICATION_USER=application \ 8 | APPLICATION_GROUP=application \ 9 | APPLICATION_PATH=/app \ 10 | APPLICATION_UID=1000 \ 11 | APPLICATION_GID=1000 12 | ENV WEB_DOCUMENT_ROOT=/app \ 13 | WEB_DOCUMENT_INDEX=index.php \ 14 | WEB_ALIAS_DOMAIN=*.vm \ 15 | WEB_PHP_TIMEOUT=600 \ 16 | WEB_PHP_SOCKET=localhost:9000 \ 17 | NGINX_CLIENT_MAX_BODY=50m \ 18 | WEB_NO_CACHE_PATTERN="\.(css|js|gif|png|jpg|svg|json|xml)$" 19 | ENV NGINX_VERSION 1.19.1 20 | ENV NGX_BROTLI_COMMIT 25f86f0bac1101b6512135eac5f93c49c63609e3 21 | ENV XDEBUG_VERSION="3.0.0" 22 | ENV IS_CLI=false 23 | ENV IS_ALPINE=true 24 | 25 | COPY conf/ /opt/docker/ 26 | # install dependencies 27 | RUN apk add --no-cache \ 28 | aom-dev \ 29 | bash-completion \ 30 | curl \ 31 | gd-dev \ 32 | geoip-dev \ 33 | git \ 34 | gnupg1 \ 35 | imagemagick \ 36 | jpegoptim \ 37 | less \ 38 | libffi-dev \ 39 | libgit2 \ 40 | libwebp-tools \ 41 | libxslt-dev \ 42 | make \ 43 | mariadb-client \ 44 | openssh \ 45 | openssl-dev \ 46 | optipng \ 47 | pcre-dev \ 48 | pngquant \ 49 | sshpass \ 50 | sudo \ 51 | supervisor \ 52 | tree \ 53 | unzip \ 54 | vim \ 55 | wget \ 56 | zip \ 57 | zlib-dev \ 58 | && apk add --no-cache --virtual .build-deps \ 59 | autoconf \ 60 | automake \ 61 | cargo \ 62 | cmake \ 63 | g++ \ 64 | gcc \ 65 | gettext \ 66 | go \ 67 | libc-dev \ 68 | libtool \ 69 | linux-headers \ 70 | musl-dev \ 71 | perl-dev \ 72 | rust 73 | 74 | 75 | # Add groups and users 76 | 77 | RUN addgroup -S nginx \ 78 | && adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx 79 | RUN addgroup -g $APPLICATION_GID $APPLICATION_GROUP \ 80 | && echo "%$APPLICATION_GROUP ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$APPLICATION_USER \ 81 | && adduser -D -u $APPLICATION_UID -s /bin/bash -G $APPLICATION_GROUP $APPLICATION_USER \ 82 | && addgroup $APPLICATION_USER nginx 83 | 84 | RUN mkdir -p /usr/src \ 85 | && cd /usr/src \ 86 | && git clone --recursive https://github.com/google/ngx_brotli.git \ 87 | && cd ngx_brotli \ 88 | && git submodule update --init --recursive \ 89 | && cd deps/brotli \ 90 | && mkdir out \ 91 | && cd out \ 92 | && cmake .. \ 93 | && make -j 16 brotli \ 94 | && cp brotli /usr/local/bin/brotli 95 | RUN cd /usr/src \ 96 | && curl -fSL https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz -o nginx.tar.gz \ 97 | && mkdir -p /usr/src \ 98 | && tar -zxC /usr/src -f nginx.tar.gz \ 99 | && rm nginx.tar.gz \ 100 | && cd /usr/src/nginx-$NGINX_VERSION \ 101 | && ls -la /usr/src/ngx_brotli \ 102 | && CONFIG=" \ 103 | --prefix=/etc/nginx \ 104 | --sbin-path=/usr/sbin/nginx \ 105 | --conf-path=/etc/nginx/nginx.conf \ 106 | --error-log-path=/var/log/nginx/error.log \ 107 | --http-log-path=/var/log/nginx/access.log \ 108 | --pid-path=/var/run/nginx.pid \ 109 | --lock-path=/var/run/nginx.lock \ 110 | --http-client-body-temp-path=/var/cache/nginx/client_temp \ 111 | --http-proxy-temp-path=/var/cache/nginx/proxy_temp \ 112 | --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ 113 | --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ 114 | --http-scgi-temp-path=/var/cache/nginx/scgi_temp \ 115 | --user=nginx \ 116 | --group=nginx \ 117 | --with-http_ssl_module \ 118 | --with-http_realip_module \ 119 | --with-http_addition_module \ 120 | --with-http_sub_module \ 121 | --with-http_dav_module \ 122 | --with-http_flv_module \ 123 | --with-http_mp4_module \ 124 | --with-http_gunzip_module \ 125 | --with-http_gzip_static_module \ 126 | --with-http_random_index_module \ 127 | --with-http_secure_link_module \ 128 | --with-http_stub_status_module \ 129 | --with-http_auth_request_module \ 130 | --with-http_xslt_module=dynamic \ 131 | --with-http_image_filter_module=dynamic \ 132 | --with-http_geoip_module=dynamic \ 133 | --with-http_perl_module=dynamic \ 134 | --with-mail \ 135 | --with-mail_ssl_module \ 136 | --with-file-aio \ 137 | --with-threads \ 138 | --with-stream \ 139 | --with-compat \ 140 | --with-stream_ssl_module \ 141 | --with-stream_realip_module \ 142 | --with-http_slice_module \ 143 | --with-http_v2_module \ 144 | --with-debug \ 145 | --add-dynamic-module=/usr/src/ngx_brotli \ 146 | " \ 147 | && ./configure $CONFIG \ 148 | && make \ 149 | && make install 150 | 151 | RUN mkdir -p /etc/nginx/modules-enabled/ \ 152 | && mkdir -p /usr/lib/nginx/modules \ 153 | && ln -s /etc/nginx/modules /usr/lib/nginx/modules \ 154 | && cd /usr/src/nginx-$NGINX_VERSION \ 155 | && cp objs/*.so /usr/lib/nginx/modules \ 156 | && echo "load_module /usr/lib/nginx/modules/ngx_http_brotli_filter_module.so;" >> /etc/nginx/modules-enabled/brotli.conf \ 157 | && echo "load_module /usr/lib/nginx/modules/ngx_http_brotli_static_module.so;" >> /etc/nginx/modules-enabled/brotli.conf \ 158 | && ln -s /usr/lib/nginx/modules /etc/nginx/modules \ 159 | && strip /usr/sbin/nginx* \ 160 | && mv /usr/bin/envsubst /tmp/ \ 161 | && runDeps="$( \ 162 | scanelf --needed --nobanner /usr/sbin/nginx /usr/lib/nginx/modules/*.so /tmp/envsubst \ 163 | | awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ 164 | | sort -u \ 165 | | xargs -r apk info --installed \ 166 | | sort -u \ 167 | )" \ 168 | && apk add --no-cache --virtual .nginx-rundeps tzdata $runDeps \ 169 | && mv /tmp/envsubst /usr/local/bin/ \ 170 | && ln -sf /dev/stdout /var/log/nginx/access.log \ 171 | && ln -sf /dev/stderr /var/log/nginx/error.log \ 172 | && mkdir -p /app/ \ 173 | && touch /app/index.html \ 174 | && echo "

It Works!

" >> /app/index.html 175 | 176 | # hadolint ignore=DL3022 177 | COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/bin/ 178 | 179 | RUN go get github.com/Kagami/go-avif \ 180 | && cd /root/go/src/github.com/Kagami/go-avif \ 181 | && make all \ 182 | && mv /root/go/bin/avif /usr/local/bin/avif 183 | 184 | STOPSIGNAL SIGQUIT 185 | 186 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer 187 | 188 | RUN curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash > /root/.git-completion.bash \ 189 | && curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh > /root/.git-prompt.sh \ 190 | && curl https://raw.githubusercontent.com/ogham/exa/master/completions/completions.bash > /root/.completions.bash 191 | 192 | USER application 193 | 194 | RUN curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash > /home/$APPLICATION_USER/.git-completion.bash \ 195 | && curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh > /home/$APPLICATION_USER/.git-prompt.sh \ 196 | && curl https://raw.githubusercontent.com/ogham/exa/master/completions/completions.bash > /home/$APPLICATION_USER/.completions.bash 197 | RUN composer global require perftools/php-profiler && composer clear 198 | COPY user/* /home/$APPLICATION_USER/ 199 | RUN echo "source ~/bashconfig.sh" >> ~/.bashrc 200 | 201 | USER root 202 | COPY user/* /root/ 203 | RUN mkdir -p /opt/php-libs 204 | COPY php/* /opt/php-libs/files/ 205 | 206 | RUN mv /opt/php-libs/files/opcache-jit.ini "$PHP_INI_DIR/conf.d/docker-php-opcache-jit.ini" \ 207 | && install-php-extensions \ 208 | xdebug-^3 \ 209 | pcov \ 210 | mongodb \ 211 | zip \ 212 | soap \ 213 | gd \ 214 | pcntl \ 215 | && docker-php-ext-install ffi \ 216 | && docker-php-ext-enable ffi 217 | RUN mv /opt/php-libs/files/pcov.ini "$PHP_INI_DIR/conf.d/docker-php-pcov.ini" \ 218 | && mkdir /tmp/debug \ 219 | && chmod -R 777 /tmp/debug \ 220 | # && mkdir -p /opt/docker/profiler \ 221 | # && mv /opt/php-libs/files/xhprof.ini "$PHP_INI_DIR/conf.d/docker-php-ext-xhprof.ini" \ 222 | && echo "ffi.enable=preload" >> "$PHP_INI_DIR/conf.d/docker-php-ffi.ini" 223 | 224 | ENV \ 225 | COMPOSER_HOME=/home/$APPLICATION_USER/.composer \ 226 | POSTFIX_RELAYHOST="[global-mail]:1025" \ 227 | PHP_DISPLAY_ERRORS="1" \ 228 | PHP_MEMORY_LIMIT="-1" \ 229 | TZ=Europe/Berlin 230 | 231 | WORKDIR /tmp 232 | 233 | ENV PATH=/usr/local/cargo/bin:$PATH 234 | 235 | RUN git clone https://github.com/ogham/exa \ 236 | && cd exa \ 237 | && cargo build --release \ 238 | && mv target/release/exa /usr/local/bin/exa \ 239 | && curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin/ \ 240 | && rm -rf /tmp/exa 241 | 242 | # hadolint ignore=DL4001 243 | RUN wget https://github.com/dalance/amber/releases/download/v0.5.8/amber-v0.5.8-x86_64-lnx.zip \ 244 | && unzip amber-v0.5.8-x86_64-lnx.zip \ 245 | && rm amber-v0.5.8-x86_64-lnx.zip \ 246 | && mv amb* /usr/local/bin/ 247 | 248 | COPY entrypoint/entrypoint.sh /entrypoint 249 | COPY entrypoint/scripts /entrypoint.d/ 250 | COPY bins/ /usr-bins/ 251 | RUN chmod +x /entrypoint.d/*.sh /entrypoint /usr-bins/* \ 252 | && mv /usr-bins/* /usr/local/bin/ \ 253 | && mkdir -p /var/log/supervisord 254 | 255 | 256 | RUN apk del .build-deps .nginx-rundeps 257 | 258 | 259 | 260 | ENTRYPOINT ["/entrypoint"] 261 | EXPOSE 80 443 9003 262 | 263 | WORKDIR /app 264 | 265 | -------------------------------------------------------------------------------- /php/opcache-jit.ini: -------------------------------------------------------------------------------- 1 | zend_extension=opcache.so 2 | opcache.enable=1 3 | opcache.enable_cli=1 4 | opcache.jit_buffer_size=32M 5 | opcache.jit=1235 6 | -------------------------------------------------------------------------------- /php/pcov.ini: -------------------------------------------------------------------------------- 1 | pcov.enabled=0 2 | pcov.exclude='~vendor~' 3 | pcov.directory=/app/ 4 | -------------------------------------------------------------------------------- /php/profiler.php: -------------------------------------------------------------------------------- 1 | Profiler::PROFILER_TIDEWAYS_XHPROF, 22 | 'profiler.flags' => [ 23 | ProfilingFlags::CPU, 24 | ProfilingFlags::MEMORY, 25 | ProfilingFlags::NO_BUILTINS, 26 | ProfilingFlags::NO_SPANS, 27 | ], 28 | 29 | 'save.handler' => Profiler::SAVER_FILE, 30 | 'save.handler.file' => array( 31 | // Appends jsonlines formatted data to this path 32 | 'filename' => getenv('PROFILING_FILE') ?: '/opt/docker/profiler/xhgui.data.jsonl', 33 | ), 34 | 35 | // Environment variables to exclude from profiling data 36 | 'profiler.exclude-env' => [ 37 | 'APP_DATABASE_PASSWORD', 38 | 'PATH', 39 | ], 40 | 41 | 'profiler.options' => [ 42 | ], 43 | 44 | /** 45 | * Determine whether profiler should run. 46 | * This default implementation just disables the profiler. 47 | * Override this with your custom logic in your config 48 | * @return bool 49 | */ 50 | 'profiler.enable' => function () { 51 | return (isset($_COOKIE['XDEBUG_PROFILE']) || getenv('PROFILING_ENABLED')); 52 | }, 53 | 54 | /** 55 | * Creates a simplified URL given a standard URL. 56 | * Does the following transformations: 57 | * 58 | * - Remove numeric values after =. 59 | * 60 | * @param string $url 61 | * @return string 62 | */ 63 | 'profile.simple_url' => function($url) { 64 | return preg_replace('/=\d+/', '', $url);; 65 | }, 66 | ]; 67 | 68 | try { 69 | /** 70 | * The constructor will throw an exception if the environment 71 | * isn't fit for profiling (extensions missing, other problems) 72 | */ 73 | $profiler = new Profiler($config); 74 | 75 | // The profiler itself checks whether it should be enabled 76 | // for request (executes lambda function from config) 77 | $profiler->enable(); 78 | 79 | // shutdown handler collects and stores the data. 80 | $profiler->registerShutdownHandler(); 81 | } catch (Exception $e){ 82 | // throw away or log error about profiling instantiation failure 83 | } 84 | -------------------------------------------------------------------------------- /php/xdebug.ini: -------------------------------------------------------------------------------- 1 | # @see https://3.xdebug.org/docs/all_settings 2 | xdebug.mode=profile,develop,coverage 3 | # xdebug.client_host = 4 | xdebug.client_port=9003 5 | xdebug.discover_client_host=1 6 | xdebug.start_with_request=default 7 | xdebug.idekey=PHPSTORM 8 | xdebug.cli_color=1 9 | xdebug.max_nesting_level=1000 10 | xdebug.output_dir=/tmp/debug 11 | -------------------------------------------------------------------------------- /php/xhprof.ini: -------------------------------------------------------------------------------- 1 | #auto_prepend_file=/opt/php-libs/files/profiler.php 2 | -------------------------------------------------------------------------------- /settings.toml: -------------------------------------------------------------------------------- 1 | template_path = "templates/" 2 | output_path = "Dockerfile" 3 | base_template = "template_dockerfile" -------------------------------------------------------------------------------- /templates/dependencies.alpine.dockerfile: -------------------------------------------------------------------------------- 1 | # install dependencies 2 | RUN apk add --no-cache \ 3 | aom-dev \ 4 | bash-completion \ 5 | curl \ 6 | gd-dev \ 7 | geoip-dev \ 8 | git \ 9 | gnupg1 \ 10 | imagemagick \ 11 | jpegoptim \ 12 | less \ 13 | libffi-dev \ 14 | libgit2 \ 15 | libwebp-tools \ 16 | libxslt-dev \ 17 | make \ 18 | mariadb-client \ 19 | openssh \ 20 | openssl-dev \ 21 | optipng \ 22 | pcre-dev \ 23 | pngquant \ 24 | sshpass \ 25 | sudo \ 26 | supervisor \ 27 | tree \ 28 | unzip \ 29 | vim \ 30 | wget \ 31 | zip \ 32 | zlib-dev \ 33 | && apk add --no-cache --virtual .build-deps \ 34 | autoconf \ 35 | automake \ 36 | cargo \ 37 | cmake \ 38 | g++ \ 39 | gcc \ 40 | gettext \ 41 | go \ 42 | libc-dev \ 43 | libtool \ 44 | linux-headers \ 45 | musl-dev \ 46 | perl-dev \ 47 | rust 48 | -------------------------------------------------------------------------------- /templates/dependencies.debian.dockerfile: -------------------------------------------------------------------------------- 1 | # install dependencies 2 | RUN apt-get update && apt-get install -y --no-install-recommends \ 3 | apt-transport-https \ 4 | autoconf \ 5 | automake \ 6 | bash-completion \ 7 | cmake \ 8 | curl \ 9 | g++ \ 10 | gcc \ 11 | gettext \ 12 | git \ 13 | gnupg1 \ 14 | golang-go\ 15 | imagemagick \ 16 | jpegoptim \ 17 | less \ 18 | libaom-dev \ 19 | libffi-dev \ 20 | libgd-dev \ 21 | libgeoip-dev \ 22 | libgit2-dev \ 23 | libpcre3 \ 24 | libpcre3-dev \ 25 | libperl-dev \ 26 | libssl-dev \ 27 | libtool \ 28 | libwebp-dev \ 29 | libxslt-dev \ 30 | make \ 31 | mariadb-client \ 32 | openssh-client \ 33 | openssl \ 34 | optipng \ 35 | pngquant \ 36 | socat \ 37 | sshpass \ 38 | sudo \ 39 | supervisor \ 40 | tree \ 41 | unzip \ 42 | vim \ 43 | wget \ 44 | zip \ 45 | && rm -rf /var/lib/apt/lists/* \ 46 | && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain stable -y 47 | -------------------------------------------------------------------------------- /templates/docker.partial.dockerfile: -------------------------------------------------------------------------------- 1 | WORKDIR /tmp 2 | 3 | ENV PATH=/usr/local/cargo/bin:$PATH 4 | 5 | RUN git clone https://github.com/ogham/exa \ 6 | && cd exa \ {{- if use_apk }} 7 | && cargo build --release \ 8 | {{- else }} 9 | && /root/.cargo/bin/cargo build --release \ 10 | {{- endif }} 11 | && mv target/release/exa /usr/local/bin/exa \ 12 | && curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin/ \ 13 | && rm -rf /tmp/exa 14 | 15 | # hadolint ignore=DL4001 16 | RUN wget https://github.com/dalance/amber/releases/download/v0.5.8/amber-v0.5.8-x86_64-lnx.zip \ 17 | && unzip amber-v0.5.8-x86_64-lnx.zip \ 18 | && rm amber-v0.5.8-x86_64-lnx.zip \ 19 | && mv amb* /usr/local/bin/ 20 | 21 | COPY entrypoint/entrypoint.sh /entrypoint 22 | COPY entrypoint/scripts /entrypoint.d/ 23 | COPY bins/ /usr-bins/ 24 | RUN chmod +x /entrypoint.d/*.sh /entrypoint /usr-bins/* \ 25 | && mv /usr-bins/* /usr/local/bin/ \ 26 | && mkdir -p /var/log/supervisord 27 | 28 | {{ if use_apk }} 29 | RUN apk del .build-deps .nginx-rundeps 30 | {{ else }} 31 | RUN rm -rf /var/lib/apt/lists/* \ 32 | && apt-get remove -y \ 33 | automake \ 34 | cmake \ 35 | g++ \ 36 | gettext \ 37 | golang-go\ 38 | libtool \ 39 | && /root/.cargo/bin/rustup self uninstall -y 40 | {{ endif }} 41 | 42 | 43 | ENTRYPOINT ["/entrypoint"] 44 | 45 | {{- if is_web }} 46 | EXPOSE 80 443 9003 47 | {{- endif }} 48 | 49 | WORKDIR /app 50 | -------------------------------------------------------------------------------- /templates/nginx.partial.dockerfile: -------------------------------------------------------------------------------- 1 | RUN mkdir -p /usr/src \ 2 | && cd /usr/src \ 3 | && git clone --recursive https://github.com/google/ngx_brotli.git \ 4 | && cd ngx_brotli \ 5 | && git submodule update --init --recursive \ 6 | && cd deps/brotli \ 7 | && mkdir out \ 8 | && cd out \ 9 | && cmake .. \ 10 | && make -j 16 brotli \ 11 | && cp brotli /usr/local/bin/brotli 12 | RUN cd /usr/src \ 13 | && curl -fSL https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz -o nginx.tar.gz \ 14 | && mkdir -p /usr/src \ 15 | && tar -zxC /usr/src -f nginx.tar.gz \ 16 | && rm nginx.tar.gz \ 17 | && cd /usr/src/nginx-$NGINX_VERSION \ 18 | && ls -la /usr/src/ngx_brotli \ 19 | && CONFIG=" \ 20 | --prefix=/etc/nginx \ 21 | --sbin-path=/usr/sbin/nginx \ 22 | --conf-path=/etc/nginx/nginx.conf \ 23 | --error-log-path=/var/log/nginx/error.log \ 24 | --http-log-path=/var/log/nginx/access.log \ 25 | --pid-path=/var/run/nginx.pid \ 26 | --lock-path=/var/run/nginx.lock \ 27 | --http-client-body-temp-path=/var/cache/nginx/client_temp \ 28 | --http-proxy-temp-path=/var/cache/nginx/proxy_temp \ 29 | --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ 30 | --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ 31 | --http-scgi-temp-path=/var/cache/nginx/scgi_temp \ 32 | --user=nginx \ 33 | --group=nginx \ 34 | --with-http_ssl_module \ 35 | --with-http_realip_module \ 36 | --with-http_addition_module \ 37 | --with-http_sub_module \ 38 | --with-http_dav_module \ 39 | --with-http_flv_module \ 40 | --with-http_mp4_module \ 41 | --with-http_gunzip_module \ 42 | --with-http_gzip_static_module \ 43 | --with-http_random_index_module \ 44 | --with-http_secure_link_module \ 45 | --with-http_stub_status_module \ 46 | --with-http_auth_request_module \ 47 | --with-http_xslt_module=dynamic \ 48 | --with-http_image_filter_module=dynamic \ 49 | --with-http_geoip_module=dynamic \ 50 | --with-http_perl_module=dynamic \ 51 | --with-mail \ 52 | --with-mail_ssl_module \ 53 | --with-file-aio \ 54 | --with-threads \ 55 | --with-stream \ 56 | --with-compat \ 57 | --with-stream_ssl_module \ 58 | --with-stream_realip_module \ 59 | --with-http_slice_module \ 60 | --with-http_v2_module \ 61 | --with-debug \ 62 | --add-dynamic-module=/usr/src/ngx_brotli \ 63 | " \ 64 | && ./configure $CONFIG \ 65 | && make \ 66 | && make install 67 | 68 | RUN mkdir -p /etc/nginx/modules-enabled/ \ 69 | && mkdir -p /usr/lib/nginx/modules \ 70 | && ln -s /etc/nginx/modules /usr/lib/nginx/modules \ 71 | && cd /usr/src/nginx-$NGINX_VERSION \ 72 | && cp objs/*.so /usr/lib/nginx/modules \ 73 | && echo "load_module /usr/lib/nginx/modules/ngx_http_brotli_filter_module.so;" >> /etc/nginx/modules-enabled/brotli.conf \ 74 | && echo "load_module /usr/lib/nginx/modules/ngx_http_brotli_static_module.so;" >> /etc/nginx/modules-enabled/brotli.conf \ 75 | && ln -s /usr/lib/nginx/modules /etc/nginx/modules \ 76 | && strip /usr/sbin/nginx* \ 77 | && mv /usr/bin/envsubst /tmp/ \ {{- if use_apk }} 78 | && runDeps="$( \ 79 | scanelf --needed --nobanner /usr/sbin/nginx /usr/lib/nginx/modules/*.so /tmp/envsubst \ 80 | | awk '\{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \ 81 | | sort -u \ 82 | | xargs -r apk info --installed \ 83 | | sort -u \ 84 | )" \ 85 | && apk add --no-cache --virtual .nginx-rundeps tzdata $runDeps \ {{- else }} 86 | && apt-get update && apt-get install -y --no-install-recommends libperl-dev python3-pip tzdata \ 87 | && rm -rf /var/lib/apt/lists/* \ {{- endif }} 88 | && mv /tmp/envsubst /usr/local/bin/ \ 89 | && ln -sf /dev/stdout /var/log/nginx/access.log \ 90 | && ln -sf /dev/stderr /var/log/nginx/error.log \ 91 | && mkdir -p /app/ \ 92 | && touch /app/index.html \ 93 | && echo "

It Works!

" >> /app/index.html -------------------------------------------------------------------------------- /templates/template.dockerfile: -------------------------------------------------------------------------------- 1 | FROM {base.from} 2 | 3 | ENV TERM="xterm" \ 4 | LANG="C.UTF-8" \ 5 | LC_ALL="C.UTF-8" 6 | ENV DOCKER_CONF_HOME=/opt/docker/ 7 | ENV APPLICATION_USER=application \ 8 | APPLICATION_GROUP=application \ 9 | APPLICATION_PATH=/app \ 10 | APPLICATION_UID=1000 \ 11 | APPLICATION_GID=1000 {{- if base.is_web }} 12 | ENV WEB_DOCUMENT_ROOT=/app \ 13 | WEB_DOCUMENT_INDEX=index.php \ 14 | WEB_ALIAS_DOMAIN=*.vm \ 15 | WEB_PHP_TIMEOUT=600 \ 16 | WEB_PHP_SOCKET=localhost:9000 \ 17 | NGINX_CLIENT_MAX_BODY=50m \ 18 | WEB_NO_CACHE_PATTERN="\.(css|js|gif|png|jpg|svg|json|xml)$" 19 | ENV NGINX_VERSION 1.19.1 20 | ENV NGX_BROTLI_COMMIT 25f86f0bac1101b6512135eac5f93c49c63609e3{{- endif }} 21 | {{ if is_dev }}ENV XDEBUG_VERSION="{base.envs.XDEBUG_VERSION}"{{ endif }} 22 | ENV IS_CLI={{- if base.is_web }}false{{- else }}true{{- endif }} 23 | ENV IS_ALPINE={{- if base.use_apk }}true{{- else }}false{{- endif }} 24 | 25 | COPY conf/ /opt/docker/ 26 | 27 | {{- if base.use_apk }} 28 | {{ call dependencies_alpine_dockerfile with base }} 29 | {{- else }} 30 | {{ call dependencies_debian_dockerfile with base }} 31 | {{- endif }} 32 | 33 | # Add groups and users 34 | {{ if base.use_apk }} 35 | RUN addgroup -S nginx \ 36 | && adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx 37 | RUN addgroup -g $APPLICATION_GID $APPLICATION_GROUP \ {{- if is_dev }} 38 | && echo "%$APPLICATION_GROUP ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$APPLICATION_USER \ {{- endif }} 39 | && adduser -D -u $APPLICATION_UID -s /bin/bash -G $APPLICATION_GROUP $APPLICATION_USER {{- if base.is_web }} \ 40 | && addgroup $APPLICATION_USER nginx {{- endif }} 41 | {{ else }} 42 | {{- if base.is_web }} 43 | RUN groupadd -g 103 nginx \ 44 | && adduser --gecos "" --disabled-password --system --home /var/cache/nginx --shell /sbin/nologin --ingroup nginx nginx {{- endif }} 45 | RUN groupadd -g $APPLICATION_GID $APPLICATION_GROUP \ {{- if is_dev }} 46 | && echo "%$APPLICATION_GROUP ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$APPLICATION_USER \ {{- endif }} 47 | && adduser --gecos "" --disabled-password --uid $APPLICATION_UID --shell /bin/bash --ingroup $APPLICATION_GROUP $APPLICATION_USER {{- if base.is_web }} \ 48 | && usermod -aG nginx $APPLICATION_USER {{- endif }} 49 | {{ endif }} 50 | 51 | {{- if base.is_web }} 52 | {{ call nginx_partial_dockerfile with base }} 53 | {{- endif }} 54 | 55 | # hadolint ignore=DL3022 56 | COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/bin/ 57 | 58 | RUN go get github.com/Kagami/go-avif \ 59 | && cd /root/go/src/github.com/Kagami/go-avif \ 60 | && make all \ 61 | && mv /root/go/bin/avif /usr/local/bin/avif 62 | 63 | STOPSIGNAL SIGQUIT 64 | 65 | RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer 66 | 67 | RUN curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash > /root/.git-completion.bash \ 68 | && curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh > /root/.git-prompt.sh \ 69 | && curl https://raw.githubusercontent.com/ogham/exa/master/completions/completions.bash > /root/.completions.bash 70 | 71 | USER application 72 | 73 | RUN curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-completion.bash > /home/$APPLICATION_USER/.git-completion.bash \ 74 | && curl https://raw.githubusercontent.com/git/git/master/contrib/completion/git-prompt.sh > /home/$APPLICATION_USER/.git-prompt.sh \ 75 | && curl https://raw.githubusercontent.com/ogham/exa/master/completions/completions.bash > /home/$APPLICATION_USER/.completions.bash 76 | RUN composer global require perftools/php-profiler && composer clear 77 | COPY user/* /home/$APPLICATION_USER/ 78 | RUN echo "source ~/bashconfig.sh" >> ~/.bashrc 79 | 80 | USER root 81 | COPY user/* /root/ 82 | RUN mkdir -p /opt/php-libs 83 | COPY php/* /opt/php-libs/files/ 84 | 85 | RUN mv /opt/php-libs/files/opcache-jit.ini "$PHP_INI_DIR/conf.d/docker-php-opcache-jit.ini" \ 86 | && install-php-extensions \ {{- if is_dev }} 87 | xdebug-^3 \ 88 | pcov \ {{- endif }} 89 | mongodb \ 90 | zip \ 91 | soap \ 92 | gd \ 93 | pcntl \ 94 | && docker-php-ext-install ffi \ 95 | && docker-php-ext-enable ffi 96 | 97 | {{- if is_dev }} 98 | RUN mv /opt/php-libs/files/pcov.ini "$PHP_INI_DIR/conf.d/docker-php-pcov.ini" \ 99 | && mkdir /tmp/debug \ 100 | && chmod -R 777 /tmp/debug \ 101 | # && mkdir -p /opt/docker/profiler \ 102 | # && mv /opt/php-libs/files/xhprof.ini "$PHP_INI_DIR/conf.d/docker-php-ext-xhprof.ini" \ 103 | && echo "ffi.enable=preload" >> "$PHP_INI_DIR/conf.d/docker-php-ffi.ini" 104 | {{- endif }} 105 | 106 | ENV \ 107 | COMPOSER_HOME=/home/$APPLICATION_USER/.composer \ 108 | POSTFIX_RELAYHOST="[global-mail]:1025" \ 109 | PHP_DISPLAY_ERRORS="1" \ 110 | PHP_MEMORY_LIMIT="-1" \ 111 | TZ=Europe/Berlin 112 | 113 | {{ call docker_partial_dockerfile with base }} 114 | -------------------------------------------------------------------------------- /user/.vimrc: -------------------------------------------------------------------------------- 1 | filetype indent plugin on 2 | syntax on 3 | set hidden 4 | -------------------------------------------------------------------------------- /user/bashconfig.sh: -------------------------------------------------------------------------------- 1 | export LS_COLORS="${LS_COLORS}di=1;34:" 2 | export EXA_COLORS="da=1;34:gm=1;34" 3 | alias ls='exa' 4 | alias ll='ls -alh --git --header --group' 5 | export PATH=$PATH:~/.composer/vendor/bin:./bin:./vendor/bin:./node_modules/.bin:/usr/local/cargo/bin 6 | source ~/.git-completion.bash 7 | source ~/.git-prompt.sh 8 | source ~/.completions.bash 9 | 10 | is_root() { 11 | return $(id -u) 12 | } 13 | 14 | has_sudo() { 15 | local prompt 16 | 17 | prompt=$(sudo -nv 2>&1) 18 | if [ $? -eq 0 ] || is_root; then 19 | return 1 20 | fi 21 | return 0 22 | } 23 | 24 | # for more information on this: https://github.com/pluswerk/php-dev/blob/master/.additional_bashrc.sh 25 | CONTAINER_ID=$(basename $(cat /proc/1/cpuset)) 26 | export HOST_DISPLAY_NAME=$HOSTNAME 27 | 28 | if has_sudo -eq 1 && [ sudo docker ps -q ] &>/dev/null; then 29 | DOCKER_COMPOSE_PROJECT=$(sudo docker inspect ${CONTAINER_ID} | grep '"com.docker.compose.project":' | awk '{print $2}' | tr -d '"' | tr -d ',') 30 | export NODE_CONTAINER=$(sudo docker ps -f "name=${DOCKER_COMPOSE_PROJECT}_node_1" --format {{.Names}}) 31 | export HOST_DISPLAY_NAME=$(sudo docker inspect ${CONTAINER_ID} --format='{{.Name}}') 32 | export HOST_DISPLAY_NAME=${HOST_DISPLAY_NAME:1} 33 | 34 | alias node_exec='sudo docker exec -u $(id -u):$(id -g) -w $(pwd) -it ${NODE_CONTAINER}' 35 | alias node_root_exec='sudo docker exec -w $(pwd) -it ${NODE_CONTAINER}' 36 | 37 | alias node='node_exec node' 38 | alias npm='node_exec npm' 39 | alias npx='node_exec npx' 40 | alias yarn='node_exec yarn' 41 | fi 42 | export HOST_DISPLAY_NAME=$HOSTNAME 43 | 44 | if [[ $CONTAINER_ID != ${HOSTNAME}* ]]; then 45 | export HOST_DISPLAY_NAME=$HOSTNAME 46 | fi 47 | 48 | PS1='\033]2;'$(pwd)'\007\[\e[0;36m\][\[\e[1;31m\]\u\[\e[0;36m\]@\[\e[1;34m\]$HOST_DISPLAY_NAME\[\e[0;36m\]: \[\e[0m\]\w\[\e[0;36m\]]\[\e[0m\]\$\[\e[1;32m\]\s\[\e[0;33m\]$(__git_ps1)\[\e[0;36m\]> \[\e[0m\]\n$ ' 49 | 50 | eval `ssh-agent -s` 51 | if [ -z "$SSH_AUTH_SOCK" ]; then 52 | ssh-add -t 604800 ~/.ssh/id_rsa 53 | else 54 | ssh-add 55 | fi 56 | 57 | export EDITOR=vim 58 | 59 | ## this extracts pretty much any archive 60 | function extract() { 61 | if [ -f $1 ]; then 62 | case $1 in 63 | *.tar.bz2) tar xvjf $1 ;; 64 | *.tar.gz) tar xvzf $1 ;; 65 | *.bz2) bunzip2 $1 ;; 66 | *.rar) unrar x $1 ;; 67 | *.gz) gunzip $1 ;; 68 | *.tar) tar xvf $1 ;; 69 | *.tbz2) tar xvjf $1 ;; 70 | *.tgz) tar xvzf $1 ;; 71 | *.zip) unzip $1 ;; 72 | *.Z) uncompress $1 ;; 73 | *.7z) 7z x $1 ;; 74 | *) echo "'$1' cannot be extracted via >extract<" ;; 75 | esac 76 | else 77 | echo "'$1' is not a valid file!" 78 | fi 79 | } 80 | 81 | function xdebug-enable() { 82 | xdebug-mode "profile,develop,coverage" 83 | } 84 | 85 | function xdebug-debug() { 86 | xdebug-mode "debug,develop" 87 | } 88 | 89 | function xdebug-disable() { 90 | xdebug-mode "off" 91 | } --------------------------------------------------------------------------------