From d8ec16ee469931c84e81e23fd600c696cb5b85c3 Mon Sep 17 00:00:00 2001 From: Marcin Orlowski Date: Thu, 14 Apr 2016 16:36:59 +0200 Subject: [PATCH] Initial release --- .gitignore | 11 ++++++ README.md | 80 ++++++++++++++++++++++++++++++++++++++ bin/process-env | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ composer.json | 30 ++++++++++++++ 4 files changed, 222 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 bin/process-env create mode 100644 composer.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..811a318 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.idea/ + +# Vagrant VM +.vagrant/ + +# Vim tmp files +*.swp + +# Composer files +vendor/ +composer.lock \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2e6457 --- /dev/null +++ b/README.md @@ -0,0 +1,80 @@ +# DotEnv building Helper # + +DotEnv file (`.env`) are often used as runtime configuration files (i.e. Laravel based PHP projects) +and are not stored in your repository, so if you use Continuous Integration (CI) tools like Team City, +you need to create that `.env` file before tests can be started. DotEnv Helper is created to help +you with step. + +The main assumption is that you usually have file like `.env.dist` in your repository (so people +know how to create production `.env`). DotEnv helper reads that file and tries to get values +for keys present in the file by looking into environmental variables or command line arguments +to produce populated, ready to use DotEnv file. Having `.env` created that way lets you keep all +needed runtime configuration (i.e. API keys etc) directly in CI configuration, in run step in Team City. + +**NOTE:** To avoid accidental overwrites this tool only echoes content of echoed file, so to create +physical `.env` file for your code you need to redirect stdout with regular ` ... > .env`. + +## Env variable subsitution ## + +Let's assume our `.env.dist` looks like this: + + KEY=val + BAR=zen + FOO= + +then knowing you want to have own value set for `KEY` you set your build +step in CI as shell script: + + export KEY=bar + vendor/bin/process-env .env.dist > .env + +which shall produce `.env` file with content as follow: + + KEY=bar + BAR=zen + FOO= + +As you noticed, original value of `KEY` is replaced with what we provided, while `BAR` +and `FOO`, for which we did not provide replacements, were copied unaltered. + + +## Argument subsitution ## + +Aside of env variables you can also pass `key=val` arguments to `process-env` achieve the same +goal: + + vendor/bin/process-env .env.dist KEY=bar > .env + +**IMPORTANT:** first argument always refers to source env file. + + +## Combined substitution ## + +Both substitution methods can be used together. When key is provided as argument and +also exists as Env variable, then command line provided value will be used: + + export KEY=bar + vendor/bin/process-env .env.dist KEY=foo > .env + +will produce: + + KEY=foo + BAR=zen + FOO= + + +## Installation ## + +Use composer to install this package as your development dependency: + + composer require --dev marcin-orlowski/dotenv-helper + + +It will install `process-env` script in usual `vendor/bin` folder. + + +## License ## + +* Written and copyrighted by Marcin Orlowski +* Response Builder is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT) + diff --git a/bin/process-env b/bin/process-env new file mode 100644 index 0000000..02767ad --- /dev/null +++ b/bin/process-env @@ -0,0 +1,101 @@ +#!//usr/bin/php -q + + * @copyright 2016 Marcin Orlowski + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link https://github.com/MarcinOrlowski/dotenv-helper + */ + +/** + * Aborts script execution with custom message and return code. + * + * @param string $msg Message to display. + * @param integer $code Code to be returned. + * + * @return void + */ +function abort($msg, $code = 1) +{ + echo $msg; + exit($code); +} + +/******************************************************/ + +if ($_SERVER['argc'] < 2) { + abort(sprintf("Usage: %s .env.dist [KEY=VAL KEY2=VAL2...]\n", $_SERVER['argv'][0])); +} + +$file_in = $_SERVER['argv'][1]; + +if (file_exists($file_in)) { + $content = file($file_in, FILE_IGNORE_NEW_LINES); + $out = []; + if ($content !== false) { + // key=val mapping built from provided arguments + $map = []; + + // if key=val mappings are given as argument, populate + // $map array with this data + if ($_SERVER['argc'] > 2) { + for ($i = 2; $i < $_SERVER['argc']; $i++) { + $entry = $_SERVER['argv'][ $i ]; + $pos = strpos($entry, '='); + if ($pos !== false) { + $key = substr($entry, 0, $pos); + $val = substr($entry, ($pos + 1)); + $map[ $key ] = $val; + } + } + } + + foreach ($content as $line) { + switch (substr(trim($line), 0, 1)) { + // copy comment lines unprocessed + case '#': + $out[] = $line; + break; + + default: + $pos = strpos($line, '='); + $new_val = null; + + // if we have assignment entry, check if there's + // anything matching in $map. If not, look for env + // variable with that name. If still nothing found + // copy it as is + if ($pos !== false) { + $key = substr($line, 0, $pos); + if (array_key_exists($key, $map)) { + $new_val = "{$key}={$map[$key]}"; + } else { + $val = getenv($key); + if ($val !== false) { + $new_val = "{$key}={$val}"; + } + } + } + + if (is_null($new_val)) { + $new_val = $line; + } + + $out[] = $new_val; + break; + } + } + + // output content of processed .env + echo implode("\n", $out); + } else { + abort("Failed processing '{$file_in}' source file\n"); + } +} else { + abort("Source file '{$file_in}' not found\n"); +} + +// done +exit(0); diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..7e6f133 --- /dev/null +++ b/composer.json @@ -0,0 +1,30 @@ +{ + "name": "marcin-orlowski/dotenv-helper", + "description": "Little tool to help build DotEnv (.env) files from templates", + "minimum-stability": "stable", + "license": "MIT", + "keywords": [ + "dotenv", + "laravel", + "helper", + "continous-integration", + "ci", + "teamcity", + "travis", + "dev-tools" + ], + "bin": [ + "bin/process-env" + ], + "authors": [ + { + "name": "Marcin Orlowski" + } + ], + "require": { + "php": ">=5.1.2" + }, + "require-dev": { + "marcin-orlowski/coding-standard": "^1.0" + } +}