helhum/dotenv-connector

Possible to make dotenv-connector loading .env for composer-scripts?

Closed this issue · 7 comments

Is it possible to make dotenv-connector loading .env for composer-scripts? It would be awesome to have any CLI compatible dotenv-bootstrap to run in composer-script:

  "scripts": {
    "load-env": "@php vendor/helhum/dotenv-connector/bin/load-env",
    "typo3-cli": [
      "@loadenv",
      "@php vendor/typo3/cms-cli/typo3"
    ],
  }

This package seems to have such a feature, but it would be kinky to double-use & define .env in composer.json.
May be integrating such an integration class with dotenv-connector would be possible?

https://github.com/bangpound/composer-dotenv

see below!

@helhum may be you would like to use my prototype for Composer DotenvEvent.

<?php
namespace TYPOworx\TnmPackageGeneric\Composer;

use Composer\Composer;
use Composer\Processor;
use Composer\IO\IOInterface;
use Composer\EventDispatcher\Event;
use Symfony\Component\Dotenv\Dotenv;

/**
 * Class DotenvEvent
 * 
 * @author Gabriel Kaufmann <info@typoworx.com>
 * @package TYPOworx\TnmPackageGeneric\Composer
 */
class DotenvEvent
{
    protected static $packageName = 'typoworx/tnm-package-generic';


    /**
     * @param \Composer\EventDispatcher\Event $event
     */
    public static function buildParameters(Event $event)
    {
        $io = $event->getIO();
        $extras = $event->getComposer()->getPackage()->getExtra();

        $config = [
            'path' => realpath(__DIR__ . '/../../../../'),
            'file' => '.env',
            'overrideEnv' => false
        ];

        if (isset($extras[ static::$packageName ]) && count($extras[ static::$packageName ]))
        {
            $config = array_merge(
                $config,
                $extras[ static::$packageName ]
            );
        }

        if (!is_array($config))
        {
            throw new \InvalidArgumentException(
                'The composer.json section extra.tnm-package-generic parameters setting must be an array or a configuration object.'
            );
        }

        $config['path'] = realpath($config['path']);

        static::loadEnv($config);

        $io->write(sprintf('<info>Using TYPO3-Context: %s</info>', getenv('TYPO3_CONTEXT') ?? 'Production'));
    }

    protected static function loadEnv(array $config)
    {
        try
        {
            $envFile = rtrim($config['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
            $envFile.= ltrim($config['file'], DIRECTORY_SEPARATOR);

            $dotenv = new Dotenv(true);
            $dotenv->populate(
                $dotenv->parse(
                    file_get_contents($envFile),
                    $envFile
                ),
                $config['overrideEnv']
            );
        }
        catch (\InvalidArgumentException $e)
        {}
    }
}

composer.json
add extra section (optional, but recommended)

note
use overrideEnv with caution! This will override existing env-vars on your system!

  "extra":{
    "typoworx/tnm-package-generic": {
      "path": "../",
      "file": ".env",
      "overrideEnv": true
    }
  },
  "scripts": {
    "typo3-cli": [
      "@load-env",
      "@php vendor/typo3/cms-cli/typo3"
    ],
    "load-env": "TYPOworx\\TnmPackageGeneric\\Composer\\DotenvEvent::buildParameters",
    "test": [
      "@load-env",
      "@php -r 'print_r(getenv(\"TYPO3_CONTEXT\"));'"
    ],
  }

A few things here:

  1. This package populates env vars mainly for the runtime of any Composer application that includes the vendor/autoload.php of the project
  2. Additionally env vars are populated in the Composer build time pre-autoload-dumo event, thus any script execute after that (e.g. in post-autoload-dump) can use the env vars
  3. I have no plans to extend this to any other state or events in Composer runtime
  4. From interpreting your attempts, this package should solve all of your needs, as you seem to be calling PHP binaries, which include (or should include) the vendor/autoload.php at their runtime

I'm closing this as well as I don't see what I can sensibly change here.

"scripts": {
    "typo3-cli": [
      "vendor/bin/typo3"
    ],
  }

This is enough to have env vars populated for TYPO3 cli.

hm. Are you shure regarding typo3-cli?
I was testing it with nc-staticfilecache CLI and it doesn't look like working.

And site-note:
for other composer-scripts the ENV isn't popuplated as well. So at least for this point it could be interesting.

edited
I can at least confirm that not all ENV-Vars are populated for composer-scripts. May be it's working inside typo3-cli but not for other scripts not being executed underneath typo3-cli. In my case I did not have the ENV TYPO3_CONTEXT defined in .env and had no TYPO3_CONTEXT for other composer-scripts trying to fetch it.

hm. Are you shure regarding typo3-cli?

Yes, I'm sure.

for other composer-scripts the ENV isn't popuplated as well. So at least for this point it could be interesting.

As I wrote: It'll work for all scripts executed in post-autoload-dump event. For others I'll stay reluctant until I have a very concrete use case.

edited
I can at least confirm that not all ENV-Vars are populated for composer-scripts. May be it's working inside typo3-cli but not for other scripts not being executed underneath typo3-cli. In my case I did not have the ENV TYPO3_CONTEXT defined in .env and had no TYPO3_CONTEXT for other composer-scripts trying to fetch it.

See above.

Maybe describe your concrete and complete use case. Otherwise I can't really understand how exposing env vars for composer scripts can be useful.

I can at least confirm that not all ENV-Vars are populated for composer-scripts.

Can you now at least confirm that (other than stated above) it is working for TYPO3 cli? That would be helpful as well.