How to configure a composer package to be globally installed?
Asked Answered
C

1

14

I'm trying to make a little CLI tool and package it up with composer.

Below is an extremely simplified version of the program, but it's enough to demonstrate the problem I'm encountering.

The project has one dependency, and one "binary" file

composer.json

{
  "name": "alice/yamldump",
  "version": "0.2.0",
  "bin": [
    "bin/yamldump"
  ],
  "require": {
    "symfony/yaml": "2.5.3"
  }
}

bin/yamldump

#!/usr/bin/env php
<?php

// use Yaml namespace
use Symfony\Component\Yaml as Yaml;

// autoload
require_once "vendor/autoload.php";

// read yaml
$yaml = file_get_contents(sprintf("%s/%s", getcwd(), $argv[1]));

// create parser
$parser = new Yaml\Parser();

// parse the yaml
var_dump($parser->parse($yaml));

So when I install it globally, I get this

$ composer global require alice/yamldump=dev-master

Files are installed to

  • ~/.composer/vendor/bin/yamldump -> ../alice/yamldump/bin/yamldump
  • ~/.composer/vendor/alice/yamldump/
  • ~/.composer/vendor/symfony/yaml/

This is a problem, because I did not intend to globally install symfony/yaml and my package's vendor/autoload.php can no longer find the Yaml package in the proper location.

I don't mind that symfony/yaml was installed globally, but it would make sense to me that composer global require would install the package like this:

  • ~/.composer/vendor/bin/yamldump -> ../alice/yamldump/bin/yamldump
  • ~/.composer/vendor/alice/yamldump/
  • ~/.composer/vendor/alice/yamldump/vendor/symfony/yaml/

After all, what if I have Package A that depends on symfony/yaml=2.5.3 and Package B that requires symfony/yaml=2.6.x?

If the composer global require installs dependencies to ~/.composer/vendor/*, each globally required package can't maintain it's own version requirement of its dependency...

I know this is sort of a convoluted problem, but I really don't know how to begin fixing it.


The goal

A user should be able to

$ composer global require alice/yamldump=dev-master
$ yamldump sample.yml

The error

$ yamldump sample.yml
Warning: require_once(vendor/autoload.php): failed to open stream: No such file or directory in /Users/alice/.composer/vendor/alice/yamldump/bin/yamldump on line 8

Fatal error: require_once(): Failed opening required 'vendor/autoload.php' (include_path='.:') in /Users/alice/.composer/vendor/alice/yamldump/bin/yamldump on line 8

The question

Here it is in black & white:

How am I intended to write the require "vendor/autoload.php" line and have it work for both locally installed packages and globally installed packages?

Crazyweed answered 22/8, 2014 at 1:22 Comment(0)
D
3

Targeting vendor/autoload.php is generally not a good idea and only works if you run the script from the correct directory. The following should serve you better:

require_once __DIR__.'/../vendor/autoload.php';

However, this still might be an issue if your application is installed as a dependency. In that case, you might need something more substantial:

if (
    (!$classLoader = includeIfExists(__DIR__.'/../vendor/autoload.php')) &&
    (!$classLoader = includeIfExists(__DIR__.'/../../../autoload.php'))
) {
    echo 'You must set up the project dependencies, run the following commands:'.PHP_EOL.
        'curl -sS https://getcomposer.org/installer | php'.PHP_EOL.
        'php composer.phar install'.PHP_EOL;
    exit(1);
}

This first looks for the autoloader in the location you would expect it to be if you are working directly on your application. If that does not exist, it looks where the autoloader would be if your application is installed as a dependency.

Dupaix answered 22/8, 2014 at 2:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.