Bläddra i källkod

Merge branch 'master' of https://github.com/composer/composer

Conflicts:
	README.md
digitalkaoz 13 år sedan
förälder
incheckning
110bd8c23f

+ 2 - 1
.gitignore

@@ -2,4 +2,5 @@
 /.project
 /.buildpath
 /composer.phar
-/vendor
+/vendor
+/nbproject

+ 9 - 5
README.md

@@ -12,7 +12,10 @@ Installation / Usage
 
 1. Download the [`composer.phar`](http://getcomposer.org/composer.phar) executable or use the installer.
 
-    $ curl http://getcomposer.org/installer | php
+    ``` sh
+    $ curl -s http://getcomposer.org/installer | php
+    ```
+
 
 2. Create a composer.json defining your dependencies. Note that this example is
 a short version for applications that are not meant to be published as packages
@@ -46,10 +49,11 @@ Since composer works with the current working directory it is possible to instal
 in a system wide way.
 
 1. Change into a directory in your path like `cd /usr/local/bin`
-2. Get composer `curl http://getcomposer.org/installer | php`
+2. Get composer `curl -s http://getcomposer.org/installer | php`
 3. Make the phar executeable `chmod a+x composer.phar`
-3. Change into a project directory `cd /path/to/my/project`
-4. Use composer as you normally would `composer.phar install`
+4. Change into a project directory `cd /path/to/my/project`
+5. Use composer as you normally would `composer.phar install`
+6. Optionally you can rename the composer.phar to composer to make it easier
 
 Global installation of composer (via homebrew)
 ----------------------------------------------
@@ -99,7 +103,7 @@ Community
 ---------
 
 The developer mailing list is on [google groups](http://groups.google.com/group/composer-dev)
-IRC channels are available for discussion as well, on irc.freenode.org [#composer](irc://irc.freenode.org/composer) 
+IRC channels are available for discussion as well, on irc.freenode.org [#composer](irc://irc.freenode.org/composer)
 for users and [#composer-dev](irc://irc.freenode.org/composer-dev) for development.
 
 Requirements

+ 5 - 6
doc/DefaultPolicy.md

@@ -27,7 +27,7 @@ Request: install A
 Packages Repo1.Av1, Repo2.Av1
 
 * priority(Repo1) >= priority(Repo2) => (Repo1.Av1, Repo2.Av1)
-* priority(Repo2) <  priority(Repo2) => (Repo2.Av1, Repo1.Av1)
+* priority(Repo1) <  priority(Repo2) => (Repo2.Av1, Repo1.Av1)
 
 ### Virtual Packages (provides)
 
@@ -39,7 +39,7 @@ Packages Av1, Bv1
 Request: install X
 
 * priority(Av1.repo) >= priority(Bv1.repo) => (Av1, Bv1)
-* priority(Av1.repo) < priority(Bv1.repo) => (Bv1, Av1)
+* priority(Av1.repo) <  priority(Bv1.repo) => (Bv1, Av1)
 
 ### Package replacements
 
@@ -49,8 +49,7 @@ Packages: Av1, Bv2
 
 Request: install A
 
-* priority(Av1.repo) > priority(Bv2.repo) => (Av1, Bv2)
-* priority(Av1.repo) = priority(Bv2.repo) => (Av1, Bv2)
-* priority(Av1.repo) < priority(Bv2.repo) => (Bv2, Av1)
+* priority(Av1.repo) >= priority(Bv2.repo) => (Av1, Bv2)
+* priority(Av1.repo) <  priority(Bv2.repo) => (Bv2, Av1)
 
-Bv2.version is ignored, only the replacement version for A matters.
+Bv2 version is ignored, only the replacement version for A matters.

+ 22 - 0
doc/faqs/packagist-update-schedule.md

@@ -0,0 +1,22 @@
+# Packagist Update Schedule
+
+## How often does Packagist crawl newly added packages?
+
+New packages will be crawled **within ten minutes**.
+
+
+## How often does Packagist crawl existing packages?
+
+Existing packages will be crawled **every hour**.
+
+
+## How often does the Packagist search index update?
+
+The search index is updated **every five minutes**. It will index (or reindex)
+any package that has been crawled since the last time the search
+indexer ran.
+
+
+## Can Packagist be triggered to recrawl a package (on commit or by other means)?
+
+Not yet. :) See [#84](https://github.com/composer/packagist/issues/84).

+ 1 - 1
src/Composer/Autoload/AutoloadGenerator.php

@@ -17,7 +17,7 @@ use Composer\Json\JsonFile;
 use Composer\Package\Loader\JsonLoader;
 use Composer\Package\PackageInterface;
 use Composer\Repository\RepositoryInterface;
-use Composer\Downloader\Util\Filesystem;
+use Composer\Util\Filesystem;
 
 /**
  * @author Igor Wiedler <igor@wiedler.ch>

+ 38 - 7
src/Composer/Autoload/ClassLoader.php

@@ -26,6 +26,9 @@ namespace Composer\Autoload;
  *     // activate the autoloader
  *     $loader->register();
  *
+ *     // to enable searching the include path (eg. for PEAR packages)
+ *     $loader->setUseIncludePath(true);
+ *
  * In this example, if you try to use a class in the Symfony\Component
  * namespace or one of its children (Symfony\Component\Console for instance),
  * the autoloader will first look for the class under the component/
@@ -41,6 +44,7 @@ class ClassLoader
 {
     private $prefixes = array();
     private $fallbackDirs = array();
+    private $useIncludePath = false;
 
     public function getPrefixes()
     {
@@ -61,7 +65,9 @@ class ClassLoader
     public function add($prefix, $paths)
     {
         if (!$prefix) {
-            $this->fallbackDirs = (array) $paths;
+            foreach ((array) $paths as $path) {
+                $this->fallbackDirs[] = $path;
+            }
             return;
         }
         if (isset($this->prefixes[$prefix])) {
@@ -74,6 +80,27 @@ class ClassLoader
         }
     }
 
+    /**
+     * Turns on searching the include for class files.
+     *
+     * @param Boolean $useIncludePath
+     */
+    public function setUseIncludePath($useIncludePath)
+    {
+        $this->useIncludePath = $useIncludePath;
+    }
+
+    /**
+     * Can be used to check if the autoloader uses the include path to check
+     * for classes.
+     *
+     * @return Boolean
+     */
+    public function getUseIncludePath()
+    {
+        return $this->useIncludePath;
+    }
+
     /**
      * Registers this instance as an autoloader.
      *
@@ -121,7 +148,7 @@ class ClassLoader
 
         if (false !== $pos = strrpos($class, '\\')) {
             // namespaced class name
-            $classPath = DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos));
+            $classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR;
             $className = substr($class, $pos + 1);
         } else {
             // PEAR-like class name
@@ -129,22 +156,26 @@ class ClassLoader
             $className = $class;
         }
 
-        $classPath .= DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
+        $classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
 
         foreach ($this->prefixes as $prefix => $dirs) {
             foreach ($dirs as $dir) {
                 if (0 === strpos($class, $prefix)) {
-                    if (file_exists($dir . $classPath)) {
-                        return $dir . $classPath;
+                    if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
+                        return $dir . DIRECTORY_SEPARATOR . $classPath;
                     }
                 }
             }
         }
 
         foreach ($this->fallbackDirs as $dir) {
-            if (file_exists($dir . $classPath)) {
-                return $dir . $classPath;
+            if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
+                return $dir . DIRECTORY_SEPARATOR . $classPath;
             }
         }
+
+        if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
+            return $file;
+        }
     }
 }

+ 2 - 2
src/Composer/Command/Command.php

@@ -25,8 +25,8 @@ abstract class Command extends BaseCommand
     /**
      * @return \Composer\Composer
      */
-    protected function getComposer()
+    protected function getComposer($required = true)
     {
-        return $this->getApplication()->getComposer();
+        return $this->getApplication()->getComposer($required);
     }
 }

+ 0 - 90
src/Composer/Command/DebugPackagesCommand.php

@@ -1,90 +0,0 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Command;
-
-use Composer\Autoload\AutoloadGenerator;
-use Composer\DependencyResolver;
-use Composer\DependencyResolver\Pool;
-use Composer\DependencyResolver\Request;
-use Composer\DependencyResolver\Operation;
-use Composer\Package\LinkConstraint\VersionConstraint;
-use Composer\Repository\CompositeRepository;
-use Composer\Repository\PlatformRepository;
-use Symfony\Component\Console\Input\InputInterface;
-use Symfony\Component\Console\Input\InputOption;
-use Symfony\Component\Console\Output\OutputInterface;
-
-/**
- * @author Jordi Boggiano <j.boggiano@seld.be>
- */
-class DebugPackagesCommand extends Command
-{
-    protected function configure()
-    {
-        $this
-            ->setName('debug:packages')
-            ->setDescription('Lists all existing packages and their version')
-            ->setDefinition(array(
-                new InputOption('local', null, InputOption::VALUE_NONE, 'list locally installed packages only'),
-                new InputOption('platform', null, InputOption::VALUE_NONE, 'list platform packages only'),
-            ))
-            ->setHelp(<<<EOT
-<info>php composer.phar debug:packages</info>
-
-EOT
-            )
-        ;
-    }
-
-    protected function execute(InputInterface $input, OutputInterface $output)
-    {
-        $composer = $this->getComposer();
-
-        // create local repo, this contains all packages that are installed in the local project
-        $localRepo = $composer->getRepositoryManager()->getLocalRepository();
-        // create installed repo, this contains all local packages + platform packages (php & extensions)
-        $installedRepo = new CompositeRepository(array($localRepo, new PlatformRepository()));
-
-        if ($input->getOption('local')) {
-            foreach ($localRepo->getPackages() as $package) {
-                $output->writeln('<info>local:</info> ' . $package->getPrettyName() . ' ' . $package->getPrettyVersion() . '<comment> (' . $package->getVersion() . ')</comment>');
-            }
-
-            return;
-        }
-
-        if ($input->getOption('platform')) {
-            $repos = array_diff($installedRepo->getPackages(), $localRepo->getPackages());
-            foreach ($repos as $package) {
-                $output->writeln('<info>plattform:</info> ' . $package->getPrettyName() . ' ' . $package->getPrettyVersion() . '<comment> (' . $package->getVersion() . ')</comment>');
-            }
-
-            return;
-        }
-
-        foreach ($installedRepo->getPackages() as $package) {
-            if ($localRepo->hasPackage($package)) {
-                $output->writeln('<info>installed:</info> ' . $package->getPrettyName() . ' ' . $package->getPrettyVersion() . '<comment> (' . $package->getVersion() . ')</comment>');
-            } else {
-                $output->writeln('<info>platform:</info> ' . $package->getPrettyName() . ' ' . $package->getPrettyVersion() . '<comment> (' . $package->getName() . ' ' . $package->getVersion() . ')</comment>');
-            }
-        }
-
-        foreach ($composer->getRepositoryManager()->getRepositories() as $repository) {
-            foreach ($repository->getPackages() as $package) {
-                $output->writeln('<comment>available:</comment> ' . $package->getPrettyName() . ' ' . $package->getPrettyVersion() . '<comment> (' . $package->getName() . ' ' . $package->getVersion() . ')</comment>');
-            }
-        }
-    }
-
-}

+ 2 - 2
src/Composer/Command/InstallCommand.php

@@ -46,7 +46,7 @@ class InstallCommand extends Command
             ->setName('install')
             ->setDescription('Parses the composer.json file and downloads the needed dependencies.')
             ->setDefinition(array(
-                new InputOption('dev', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
+                new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
                 new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
                 new InputOption('no-install-recommends', null, InputOption::VALUE_NONE, 'Do not install recommended packages (ignored when installing from an existing lock file).'),
                 new InputOption('install-suggests', null, InputOption::VALUE_NONE, 'Also install suggested packages (ignored when installing from an existing lock file).'),
@@ -73,7 +73,7 @@ EOT
             $io,
             $composer,
             $eventDispatcher,
-            (Boolean)$input->getOption('dev'),
+            (Boolean)$input->getOption('prefer-source'),
             (Boolean)$input->getOption('dry-run'),
             (Boolean)$input->getOption('verbose'),
             (Boolean)$input->getOption('no-install-recommends'),

+ 5 - 2
src/Composer/Command/SelfUpdateCommand.php

@@ -13,6 +13,7 @@
 namespace Composer\Command;
 
 use Composer\Composer;
+use Composer\Util\StreamContextFactory;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
 
@@ -39,7 +40,9 @@ EOT
 
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $latest = trim(file_get_contents('http://getcomposer.org/version'));
+        $ctx = StreamContextFactory::getContext();
+
+        $latest = trim(file_get_contents('http://getcomposer.org/version'), false, $ctx);
 
         if (Composer::VERSION !== $latest) {
             $output->writeln(sprintf("Updating to version <info>%s</info>.", $latest));
@@ -47,7 +50,7 @@ EOT
             $remoteFilename = 'http://getcomposer.org/composer.phar';
             $localFilename = $_SERVER['argv'][0];
 
-            file_put_contents($localFilename, file_get_contents($remoteFilename));
+            copy($remoteFilename, $localFilename, $ctx);
         } else {
             $output->writeln("<info>You are using the latest composer version.</info>");
         }

+ 65 - 35
src/Composer/Command/ShowCommand.php

@@ -16,7 +16,12 @@ use Composer\Composer;
 use Composer\Package\PackageInterface;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Output\OutputInterface;
+use Composer\Repository\CompositeRepository;
+use Composer\Repository\PlatformRepository;
+use Composer\Repository\ComposerRepository;
+use Composer\Repository\RepositoryInterface;
 
 /**
  * @author Robert Schönthal <seroscho@googlemail.com>
@@ -28,14 +33,16 @@ class ShowCommand extends Command
     {
         $this
             ->setName('show')
-            ->setDescription('Show package details')
+            ->setDescription('Show information about packages')
             ->setDefinition(array(
-                new InputArgument('package', InputArgument::REQUIRED, 'the package to inspect'),
-                new InputArgument('version', InputArgument::OPTIONAL, 'the version'),
+                new InputArgument('package', InputArgument::OPTIONAL, 'Package to inspect'),
+                new InputArgument('version', InputArgument::OPTIONAL, 'Version to inspect'),
+                new InputOption('installed', null, InputOption::VALUE_NONE, 'List installed packages only'),
+                new InputOption('platform', null, InputOption::VALUE_NONE, 'List platform packages only'),
             ))
             ->setHelp(<<<EOT
-The show command displays detailed information about a package
-<info>php composer.phar show composer/composer master-dev</info>
+The show command displays detailed information about a package, or
+lists all packages available.
 
 EOT
             )
@@ -44,16 +51,48 @@ EOT
 
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $composer = $this->getComposer();
-        $package = $this->getPackage($input, $output, $composer);
-        if (!$package) {
-            throw new \InvalidArgumentException('no package found');
+        // init repos
+        $platformRepo = new PlatformRepository;
+        if ($input->getOption('platform')) {
+            $repos = $installedRepo = $platformRepo;
+        } elseif ($input->getOption('installed')) {
+            $composer = $this->getComposer();
+            $repos = $installedRepo = $composer->getRepositoryManager()->getLocalRepository();
+        } elseif ($composer = $this->getComposer(false)) {
+            $localRepo = $composer->getRepositoryManager()->getLocalRepository();
+            $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
+            $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
+        } else {
+            $output->writeln('No composer.json found in the current directory, showing packages from packagist.org');
+            $installedRepo = $platformRepo;
+            $repos = new CompositeRepository(array($installedRepo, new ComposerRepository(array('url' => 'http://packagist.org'))));
         }
 
-        $this->printMeta($input, $output, $package, $composer);
-        $this->printLinks($input, $output, $package, 'requires');
-        $this->printLinks($input, $output, $package, 'recommends');
-        $this->printLinks($input, $output, $package, 'replaces');
+        // show single package or single version
+        if ($input->getArgument('package')) {
+            $package = $this->getPackage($input, $output, $installedRepo, $repos);
+            if (!$package) {
+                throw new \InvalidArgumentException('Package '.$input->getArgument('package').' not found');
+            }
+
+            $this->printMeta($input, $output, $package, $installedRepo, $repos);
+            $this->printLinks($input, $output, $package, 'requires');
+            $this->printLinks($input, $output, $package, 'recommends');
+            $this->printLinks($input, $output, $package, 'replaces');
+            return;
+        }
+
+        // list packages
+        foreach ($repos->getPackages() as $package) {
+            if ($platformRepo->hasPackage($package)) {
+                $type = '<info>platform: </info> ';
+            } elseif ($installedRepo->hasPackage($package)) {
+                $type = '<info>installed:</info> ';
+            } else {
+                $type = '<comment>available:</comment> ';
+            }
+            $output->writeln($type . ' ' . $package->getPrettyName() . ' ' . $package->getPrettyVersion() . '<comment> (' . $package->getVersion() . ')</comment>');
+        }
     }
 
     /**
@@ -63,16 +102,15 @@ EOT
      * @return PackageInterface
      * @throws \InvalidArgumentException
      */
-    protected function getPackage(InputInterface $input, OutputInterface $output, Composer $composer)
+    protected function getPackage(InputInterface $input, OutputInterface $output, RepositoryInterface $installedRepo, RepositoryInterface $repos)
     {
         // we have a name and a version so we can use ::findPackage
         if ($input->getArgument('version')) {
-            return $composer->getRepositoryManager()->findPackage($input->getArgument('package'), $input->getArgument('version'));
+            return $repos->findPackage($input->getArgument('package'), $input->getArgument('version'));
         }
 
         // check if we have a local installation so we can grab the right package/version
-        $localRepo = $composer->getRepositoryManager()->getLocalRepository();
-        foreach ($localRepo->getPackages() as $package) {
+        foreach ($installedRepo->getPackages() as $package) {
             if ($package->getName() === $input->getArgument('package')) {
                 return $package;
             }
@@ -80,15 +118,9 @@ EOT
 
         // we only have a name, so search for the highest version of the given package
         $highestVersion = null;
-        $repos = array_merge(
-            array($composer->getRepositoryManager()->getLocalRepository()),
-            $composer->getRepositoryManager()->getRepositories()
-        );
-        foreach ($repos as $repository) {
-            foreach ($repository->findPackagesByName($input->getArgument('package')) as $package) {
-                if (null === $highestVersion || version_compare($package->getVersion(), $highestVersion->getVersion(), '>=')) {
-                    $highestVersion = $package;
-                }
+        foreach ($repos->findPackagesByName($input->getArgument('package')) as $package) {
+            if (null === $highestVersion || version_compare($package->getVersion(), $highestVersion->getVersion(), '>=')) {
+                $highestVersion = $package;
             }
         }
 
@@ -98,15 +130,15 @@ EOT
     /**
      * prints package meta data
      */
-    protected function printMeta(InputInterface $input, OutputInterface $output, PackageInterface $package, Composer $composer)
+    protected function printMeta(InputInterface $input, OutputInterface $output, PackageInterface $package, RepositoryInterface $installedRepo, RepositoryInterface $repos)
     {
         $output->writeln('<info>name</info>     : ' . $package->getPrettyName());
-        $this->printVersions($input, $output, $package, $composer);
+        $this->printVersions($input, $output, $package, $installedRepo, $repos);
         $output->writeln('<info>type</info>     : ' . $package->getType());
         $output->writeln('<info>names</info>    : ' . join(', ', $package->getNames()));
         $output->writeln('<info>source</info>   : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference()));
         $output->writeln('<info>dist</info>     : ' . sprintf('[%s] <comment>%s</comment> %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference()));
-        $output->writeln('<info>licence</info>  : ' . join(', ', $package->getLicense()));
+        $output->writeln('<info>license</info>  : ' . join(', ', $package->getLicense()));
 
         if ($package->getAutoload()) {
             $output->writeln("\n<info>autoload</info>");
@@ -123,7 +155,7 @@ EOT
     /**
      * prints all available versions of this package and highlights the installed one if any
      */
-    protected function printVersions(InputInterface $input, OutputInterface $output, PackageInterface $package, Composer $composer)
+    protected function printVersions(InputInterface $input, OutputInterface $output, PackageInterface $package, RepositoryInterface $installedRepo, RepositoryInterface $repos)
     {
         if ($input->getArgument('version')) {
             $output->writeln('<info>version</info>  : ' . $package->getPrettyVersion());
@@ -132,16 +164,14 @@ EOT
 
         $versions = array();
 
-        foreach ($composer->getRepositoryManager()->getRepositories() as $repository) {
-            foreach ($repository->findPackagesByName($package->getName()) as $version) {
-                $versions[] = $version->getPrettyVersion();
-            }
+        foreach ($repos->findPackagesByName($package->getName()) as $version) {
+            $versions[] = $version->getPrettyVersion();
         }
 
         $versions = join(', ', $versions);
 
         // highlight installed version
-        if ($composer->getRepositoryManager()->getLocalRepository()->hasPackage($package)) {
+        if ($installedRepo->hasPackage($package)) {
             $versions = str_replace($package->getPrettyVersion(), '<info>* ' . $package->getPrettyVersion() . '</info>', $versions);
         }
 

+ 2 - 2
src/Composer/Command/UpdateCommand.php

@@ -35,7 +35,7 @@ class UpdateCommand extends Command
             ->setName('update')
             ->setDescription('Updates your dependencies to the latest version, and updates the composer.lock file.')
             ->setDefinition(array(
-                new InputOption('dev', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
+                new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
                 new InputOption('dry-run', null, InputOption::VALUE_NONE, 'Outputs the operations but will not execute anything (implicitly enables --verbose).'),
                 new InputOption('no-install-recommends', null, InputOption::VALUE_NONE, 'Do not install recommended packages.'),
                 new InputOption('install-suggests', null, InputOption::VALUE_NONE, 'Also install suggested packages.'),
@@ -63,7 +63,7 @@ EOT
             $io,
             $composer,
             $eventDispatcher,
-            (Boolean)$input->getOption('dev'),
+            (Boolean)$input->getOption('prefer-source'),
             (Boolean)$input->getOption('dry-run'),
             (Boolean)$input->getOption('verbose'),
             (Boolean)$input->getOption('no-install-recommends'),

+ 7 - 4
src/Composer/Console/Application.php

@@ -71,14 +71,18 @@ class Application extends BaseApplication
     /**
      * @return Composer
      */
-    public function getComposer()
+    public function getComposer($required = true)
     {
         if (null === $this->composer) {
             try {
                 $this->composer = Factory::create($this->io);
             } catch (\InvalidArgumentException $e) {
-                $this->io->write($e->getMessage());
-                exit(1);
+                if ($required) {
+                    $this->io->write($e->getMessage());
+                    exit(1);
+                }
+
+                return;
             }
         }
 
@@ -102,7 +106,6 @@ class Application extends BaseApplication
         $this->add(new Command\DependsCommand());
         $this->add(new Command\InstallCommand());
         $this->add(new Command\UpdateCommand());
-        $this->add(new Command\DebugPackagesCommand());
         $this->add(new Command\SearchCommand());
         $this->add(new Command\ValidateCommand());
         $this->add(new Command\ShowCommand());

+ 3 - 2
src/Composer/Downloader/DownloadManager.php

@@ -14,6 +14,7 @@ namespace Composer\Downloader;
 
 use Composer\Package\PackageInterface;
 use Composer\Downloader\DownloaderInterface;
+use Composer\Util\Filesystem;
 
 /**
  * Downloaders manager.
@@ -134,9 +135,9 @@ class DownloadManager
             );
         }
 
-        $fs = new Util\Filesystem();
+        $fs = new Filesystem();
         $fs->ensureDirectoryExists($targetDir);
-        
+
         $downloader = $this->getDownloaderForInstalledPackage($package);
         $downloader->download($package, $targetDir);
     }

+ 7 - 22
src/Composer/Downloader/FileDownloader.php

@@ -13,6 +13,8 @@ namespace Composer\Downloader;
 
 use Composer\IO\IOInterface;
 use Composer\Package\PackageInterface;
+use Composer\Util\Filesystem;
+use Composer\Util\StreamContextFactory;
 
 /**
  * Base downloader for file packages
@@ -77,31 +79,14 @@ abstract class FileDownloader implements DownloaderInterface
             }
         }
 
-        // Handle system proxy
-        $params = array('http' => array());
-
-        if (isset($_SERVER['HTTP_PROXY'])) {
-            // http(s):// is not supported in proxy
-            $proxy = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $_SERVER['HTTP_PROXY']);
-
-            if (0 === strpos($proxy, 'ssl:') && !extension_loaded('openssl')) {
-                throw new \RuntimeException('You must enable the openssl extension to use a proxy over https');
-            }
-
-            $params['http'] = array(
-                'proxy'           => $proxy,
-                'request_fulluri' => true,
-            );
-        }
-
+        $options = array();
         if ($this->io->hasAuthorization($package->getSourceUrl())) {
             $auth = $this->io->getAuthorization($package->getSourceUrl());
             $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
-            $params['http'] = array_merge($params['http'], array('header' => "Authorization: Basic $authStr\r\n"));
+            $options['http']['header'] = "Authorization: Basic $authStr\r\n";
         }
 
-        $ctx = stream_context_create($params);
-        stream_context_set_params($ctx, array("notification" => array($this, 'callbackGet')));
+        $ctx = StreamContextFactory::getContext($options, array('notification' => array($this, 'callbackGet')));
 
         $this->io->overwrite("    Downloading: <comment>connection...</comment>", false);
         @copy($url, $fileName, $ctx);
@@ -142,7 +127,7 @@ abstract class FileDownloader implements DownloaderInterface
      */
     public function update(PackageInterface $initial, PackageInterface $target, $path)
     {
-        $fs = new Util\Filesystem();
+        $fs = new Filesystem();
         $fs->removeDirectory($path);
         $this->download($target, $path);
     }
@@ -152,7 +137,7 @@ abstract class FileDownloader implements DownloaderInterface
      */
     public function remove(PackageInterface $package, $path)
     {
-        $fs = new Util\Filesystem();
+        $fs = new Filesystem();
         $fs->removeDirectory($path);
     }
 

+ 2 - 1
src/Composer/Downloader/VcsDownloader.php

@@ -15,6 +15,7 @@ namespace Composer\Downloader;
 use Composer\Package\PackageInterface;
 use Composer\Util\ProcessExecutor;
 use Composer\IO\IOInterface;
+use Composer\Util\Filesystem;
 
 /**
  * @author Jordi Boggiano <j.boggiano@seld.be>
@@ -73,7 +74,7 @@ abstract class VcsDownloader implements DownloaderInterface
     public function remove(PackageInterface $package, $path)
     {
         $this->enforceCleanDirectory($path);
-        $fs = new Util\Filesystem();
+        $fs = new Filesystem();
         $fs->removeDirectory($path);
     }
 

+ 9 - 3
src/Composer/Installer/LibraryInstaller.php

@@ -17,7 +17,7 @@ use Composer\Downloader\DownloadManager;
 use Composer\Repository\WritableRepositoryInterface;
 use Composer\DependencyResolver\Operation\OperationInterface;
 use Composer\Package\PackageInterface;
-use Composer\Downloader\Util\Filesystem;
+use Composer\Util\Filesystem;
 
 /**
  * Package installation manager.
@@ -147,6 +147,12 @@ class LibraryInstaller implements InstallerInterface
         foreach ($package->getBinaries() as $bin) {
             $link = $this->binDir.'/'.basename($bin);
             if (file_exists($link)) {
+                if (is_link($link)) {
+                    // likely leftover from a previous install, make sure
+                    // that the target is still executable in case this
+                    // is a fresh install of the vendor.
+                    chmod($link, 0755);
+                }
                 $this->io->write('Skipped installation of '.$bin.' for package '.$package->getName().', name conflicts with an existing file');
                 continue;
             }
@@ -156,14 +162,14 @@ class LibraryInstaller implements InstallerInterface
                 // add unixy support for cygwin and similar environments
                 if ('.bat' !== substr($bin, -4)) {
                     file_put_contents($link, $this->generateUnixyProxyCode($bin, $link));
-                    chmod($link, 0777);
+                    chmod($link, 0755);
                     $link .= '.bat';
                 }
                 file_put_contents($link, $this->generateWindowsProxyCode($bin, $link));
             } else {
                 symlink($bin, $link);
             }
-            chmod($link, 0777);
+            chmod($link, 0755);
         }
     }
 

+ 6 - 4
src/Composer/Json/JsonFile.php

@@ -14,6 +14,7 @@ namespace Composer\Json;
 
 use Composer\Repository\RepositoryManager;
 use Composer\Composer;
+use Composer\Util\StreamContextFactory;
 
 /**
  * Reads/writes json files.
@@ -59,11 +60,12 @@ class JsonFile
      */
     public function read()
     {
-        $context = stream_context_create(array(
-            'http' => array('header' => 'User-Agent: Composer/'.Composer::VERSION."\r\n")
-        ));
+        $ctx = StreamContextFactory::getContext(array(
+            'http' => array(
+                'header' => 'User-Agent: Composer/'.Composer::VERSION."\r\n"
+        )));
 
-        $json = file_get_contents($this->path, false, $context);
+        $json = file_get_contents($this->path, false, $ctx);
         if (!$json) {
             throw new \RuntimeException('Could not read '.$this->path.', you are probably offline');
         }

+ 9 - 0
src/Composer/Package/Dumper/ArrayDumper.php

@@ -24,11 +24,16 @@ class ArrayDumper
     {
         $keys = array(
             'binaries' => 'bin',
+            'scripts',
             'type',
             'names',
             'extra',
             'installationSource' => 'installation-source',
             'license',
+            'authors',
+            'description',
+            'homepage',
+            'keywords',
             'autoload',
             'repositories',
         );
@@ -41,6 +46,10 @@ class ArrayDumper
             $data['target-dir'] = $package->getTargetDir();
         }
 
+        if ($package->getReleaseDate()) {
+            $data['time'] = $package->getReleaseDate()->format('Y-m-d H:i:s');
+        }
+
         if ($package->getSourceType()) {
             $data['source']['type'] = $package->getSourceType();
             $data['source']['url'] = $package->getSourceUrl();

+ 1 - 1
src/Composer/Package/MemoryPackage.php

@@ -438,7 +438,7 @@ class MemoryPackage extends BasePackage
      *
      * @param DateTime $releaseDate
      */
-    public function setReleasedate(\DateTime $releaseDate)
+    public function setReleaseDate(\DateTime $releaseDate)
     {
         $this->releaseDate = $releaseDate;
     }

+ 200 - 58
src/Composer/Repository/PearRepository.php

@@ -13,6 +13,7 @@
 namespace Composer\Repository;
 
 use Composer\Package\Loader\ArrayLoader;
+use Composer\Util\StreamContextFactory;
 
 /**
  * @author Benjamin Eberlei <kontakt@beberlei.de>
@@ -20,7 +21,8 @@ use Composer\Package\Loader\ArrayLoader;
  */
 class PearRepository extends ArrayRepository
 {
-    protected $url;
+    private $url;
+    private $streamContext;
 
     public function __construct(array $config)
     {
@@ -31,7 +33,7 @@ class PearRepository extends ArrayRepository
             throw new \UnexpectedValueException('Invalid url given for PEAR repository: '.$config['url']);
         }
 
-        $this->url = $config['url'];
+        $this->url = rtrim($config['url'], '/');
     }
 
     protected function initialize()
@@ -41,6 +43,7 @@ class PearRepository extends ArrayRepository
         set_error_handler(function($severity, $message, $file, $line) {
             throw new \ErrorException($message, $severity, $severity, $file, $line);
         });
+        $this->streamContext = StreamContextFactory::getContext();
         $this->fetchFromServer();
         restore_error_handler();
     }
@@ -51,24 +54,62 @@ class PearRepository extends ArrayRepository
         $categories = $categoryXML->getElementsByTagName("c");
 
         foreach ($categories as $category) {
-            $categoryLink = $category->getAttribute("xlink:href");
-            $categoryLink = str_replace("info.xml", "packages.xml", $categoryLink);
-            if ('/' !== substr($categoryLink, 0, 1)) {
-                $categoryLink = '/' . $categoryLink;
+            $link = '/' . ltrim($category->getAttribute("xlink:href"), '/');
+            try {
+                $packagesLink = str_replace("info.xml", "packagesinfo.xml", $link);
+                $this->fetchPear2Packages($this->url . $packagesLink);
+            } catch (\ErrorException $e) {
+                if (false === strpos($e->getMessage(), '404')) {
+                    throw $e;
+                }
+                $categoryLink = str_replace("info.xml", "packages.xml", $link);
+                $this->fetchPearPackages($this->url . $categoryLink);
             }
-            $packagesXML = $this->requestXml($this->url . $categoryLink);
 
-            $packages = $packagesXML->getElementsByTagName('p');
-            $loader = new ArrayLoader();
-            foreach ($packages as $package) {
-                $packageName = $package->nodeValue;
+        }
+    }
 
-                $packageLink = $package->getAttribute('xlink:href');
-                $releaseLink = $this->url . str_replace("/rest/p/", "/rest/r/", $packageLink);
-                $allReleasesLink = $releaseLink . "/allreleases2.xml";
+    /**
+     * @param   string $categoryLink
+     * @throws  ErrorException
+     * @throws  InvalidArgumentException
+     */
+    private function fetchPearPackages($categoryLink)
+    {
+        $packagesXML = $this->requestXml($categoryLink);
+        $packages = $packagesXML->getElementsByTagName('p');
+        $loader = new ArrayLoader();
+        foreach ($packages as $package) {
+            $packageName = $package->nodeValue;
+
+            $packageLink = $package->getAttribute('xlink:href');
+            $releaseLink = $this->url . str_replace("/rest/p/", "/rest/r/", $packageLink);
+            $allReleasesLink = $releaseLink . "/allreleases2.xml";
+
+            try {
+                $releasesXML = $this->requestXml($allReleasesLink);
+            } catch (\ErrorException $e) {
+                if (strpos($e->getMessage(), '404')) {
+                    continue;
+                }
+                throw $e;
+            }
+
+            $releases = $releasesXML->getElementsByTagName('r');
+
+            foreach ($releases as $release) {
+                /* @var $release \DOMElement */
+                $pearVersion = $release->getElementsByTagName('v')->item(0)->nodeValue;
+
+                $packageData = array(
+                    'name' => $packageName,
+                    'type' => 'library',
+                    'dist' => array('type' => 'pear', 'url' => $this->url.'/get/'.$packageName.'-'.$pearVersion.".tgz"),
+                    'version' => $pearVersion,
+                );
 
                 try {
-                    $releasesXML = $this->requestXml($allReleasesLink);
+                    $deps = file_get_contents($releaseLink . "/deps.".$pearVersion.".txt", false, $this->streamContext);
                 } catch (\ErrorException $e) {
                     if (strpos($e->getMessage(), '404')) {
                         continue;
@@ -76,54 +117,155 @@ class PearRepository extends ArrayRepository
                     throw $e;
                 }
 
-                $releases = $releasesXML->getElementsByTagName('r');
+                $packageData += $this->parseDependencies($deps);
 
-                foreach ($releases as $release) {
-                    /* @var $release DOMElement */
-                    $pearVersion = $release->getElementsByTagName('v')->item(0)->nodeValue;
+                try {
+                    $this->addPackage($loader->load($packageData));
+                } catch (\UnexpectedValueException $e) {
+                    continue;
+                }
+            }
+        }
+    }
 
-                    $packageData = array(
-                        'name' => $packageName,
-                        'type' => 'library',
-                        'dist' => array('type' => 'pear', 'url' => $this->url.'/get/'.$packageName.'-'.$pearVersion.".tgz"),
-                        'version' => $pearVersion,
-                    );
+    /**
+     * @param   array $data
+     * @return  string
+     */
+    private function parseVersion(array $data)
+    {
+        if (!isset($data['min']) && !isset($data['max'])) {
+            return '*';
+        }
+        $versions = array();
+        if (isset($data['min'])) {
+            $versions[] = '>=' . $data['min'];
+        }
+        if (isset($data['max'])) {
+            $versions[] = '<=' . $data['max'];
+        }
+        return implode(',', $versions);
+    }
 
-                    try {
-                        $deps = file_get_contents($releaseLink . "/deps.".$pearVersion.".txt");
-                    } catch (\ErrorException $e) {
-                        if (strpos($e->getMessage(), '404')) {
-                            continue;
-                        }
-                        throw $e;
+    /**
+     * @todo    Improve dependencies resolution of pear packages.
+     * @param   array $options
+     * @return  array
+     */
+    private function parseDependenciesOptions(array $depsOptions)
+    {
+        $data = array();
+        foreach ($depsOptions as $name => $options) {
+            // make sure single deps are wrapped in an array
+            if (isset($options['name'])) {
+                $options = array($options);
+            }
+            if ('php' == $name) {
+                $data[$name] = $this->parseVersion($options);
+            } elseif ('package' == $name) {
+                foreach ($options as $key => $value) {
+                    if (is_array($value)) {
+                        $dataKey = $value['name'];
+                        $data[$dataKey] = $this->parseVersion($value);
                     }
+                }
+            } elseif ('extension' == $name) {
+                foreach ($options as $key => $value) {
+                    $dataKey = 'ext-' . $value['name'];
+                    $data[$dataKey] = $this->parseVersion($value);
+                }
+            }
+        }
+        return $data;
+    }
 
-                    if (preg_match('((O:([0-9])+:"([^"]+)"))', $deps, $matches)) {
-                        if (strlen($matches[3]) == $matches[2]) {
-                            throw new \InvalidArgumentException("Invalid dependency data, it contains serialized objects.");
-                        }
-                    }
-                    $deps = unserialize($deps);
-                    if (isset($deps['required']['package'])) {
-
-                        if (isset($deps['required']['package']['name'])) {
-                            $deps['required']['package'] = array($deps['required']['package']);
-                        }
-
-                        foreach ($deps['required']['package'] as $dependency) {
-                            if (isset($dependency['min'])) {
-                                $packageData['require'][$dependency['name']] = '>='.$dependency['min'];
-                            } else {
-                                $packageData['require'][$dependency['name']] = '>=0.0.0';
-                            }
-                        }
-                    }
+    /**
+     * @param   string $deps
+     * @return  array
+     * @throws  InvalidArgumentException
+     */
+    private function parseDependencies($deps)
+    {
+        if (preg_match('((O:([0-9])+:"([^"]+)"))', $deps, $matches)) {
+            if (strlen($matches[3]) == $matches[2]) {
+                throw new \InvalidArgumentException("Invalid dependency data, it contains serialized objects.");
+            }
+        }
+        $deps = (array) @unserialize($deps);
+        unset($deps['required']['pearinstaller']);
 
-                    try {
-                        $this->addPackage($loader->load($packageData));
-                    } catch (\UnexpectedValueException $e) {
-                        continue;
-                    }
+        $depsData = array();
+        if (!empty($deps['required'])) {
+            $depsData['require'] = $this->parseDependenciesOptions($deps['required']);
+        }
+
+        if (!empty($deps['optional'])) {
+            $depsData['suggest'] = $this->parseDependenciesOptions($deps['optional']);
+        }
+
+        return $depsData;
+    }
+
+    /**
+     * @param   string $packagesLink
+     * @return  void
+     * @throws  InvalidArgumentException
+     */
+    private function fetchPear2Packages($packagesLink)
+    {
+        $loader = new ArrayLoader();
+        $packagesXml = $this->requestXml($packagesLink);
+        $informations = $packagesXml->getElementsByTagName('pi');
+        foreach ($informations as $information) {
+            $package = $information->getElementsByTagName('p')->item(0);
+
+            $packageName = $package->getElementsByTagName('n')->item(0)->nodeValue;
+            $packageData = array(
+                'name' => $packageName,
+                'type' => 'library'
+            );
+            $packageKeys = array('l' => 'license', 'd' => 'description');
+            foreach ($packageKeys as $pear => $composer) {
+                if ($package->getElementsByTagName($pear)->length > 0
+                        && ($pear = $package->getElementsByTagName($pear)->item(0)->nodeValue)) {
+                    $packageData[$composer] = $pear;
+                }
+            }
+
+            $depsData = array();
+            foreach ($information->getElementsByTagName('deps') as $depElement) {
+                $depsVersion = $depElement->getElementsByTagName('v')->item(0)->nodeValue;
+                $depsData[$depsVersion] = $this->parseDependencies(
+                    $depElement->getElementsByTagName('d')->item(0)->nodeValue
+                );
+            }
+
+            $releases = $information->getElementsByTagName('a')->item(0);
+            if (!$releases) {
+                continue;
+            }
+
+            $releases = $releases->getElementsByTagName('r');
+            $packageUrl = $this->url . '/get/' . $packageName;
+            foreach ($releases as $release) {
+                $version = $release->getElementsByTagName('v')->item(0)->nodeValue;
+                $releaseData = array(
+                    'dist' => array(
+                        'type' => 'pear',
+                        'url' => $packageUrl . '-' . $version . '.tgz'
+                    ),
+                    'version' => $version
+                );
+                if (isset($depsData[$version])) {
+                    $releaseData += $depsData[$version];
+                }
+
+                try {
+                    $this->addPackage(
+                        $loader->load($packageData + $releaseData)
+                    );
+                } catch (\UnexpectedValueException $e) {
+                    continue;
                 }
             }
         }
@@ -135,7 +277,7 @@ class PearRepository extends ArrayRepository
      */
     private function requestXml($url)
     {
-        $content = file_get_contents($url);
+        $content = file_get_contents($url, false, $this->streamContext);
         if (!$content) {
             throw new \UnexpectedValueException('The PEAR channel at '.$url.' did not respond.');
         }

+ 1 - 3
src/Composer/Downloader/Util/Filesystem.php → src/Composer/Util/Filesystem.php

@@ -10,9 +10,7 @@
  * file that was distributed with this source code.
  */
 
-namespace Composer\Downloader\Util;
-
-use Composer\Util\ProcessExecutor;
+namespace Composer\Util;
 
 /**
  * @author Jordi Boggiano <j.boggiano@seld.be>

+ 56 - 0
src/Composer/Util/StreamContextFactory.php

@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Util;
+
+/**
+ * Allows the creation of a basic context supporting http proxy
+ *
+ * @author Jordan Alliot <jordan.alliot@gmail.com>
+ */
+final class StreamContextFactory
+{
+    /**
+     * Creates a context supporting HTTP proxies
+     *
+     * @param array $defaultOptions Options to merge with the default
+     * @param array $defaultParams  Parameters to specify on the context
+     * @return resource Default context
+     * @throws \RuntimeException if https proxy required and OpenSSL uninstalled
+     */
+    static public function getContext(array $defaultOptions = array(), array $defaultParams = array())
+    {
+        $options = array('http' => array());
+
+        // Handle system proxy
+        if (isset($_SERVER['HTTP_PROXY']) || isset($_SERVER['http_proxy'])) {
+            // Some systems seem to rely on a lowercased version instead...
+            $proxy = isset($_SERVER['HTTP_PROXY']) ? $_SERVER['HTTP_PROXY'] : $_SERVER['http_proxy'];
+            
+            // http(s):// is not supported in proxy
+            $proxy = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxy);
+
+            if (0 === strpos($proxy, 'ssl:') && !extension_loaded('openssl')) {
+                throw new \RuntimeException('You must enable the openssl extension to use a proxy over https');
+            }
+            
+            $options['http'] = array(
+                'proxy'           => $proxy,
+                'request_fulluri' => true,
+            );
+        }
+
+        $options = array_merge_recursive($options, $defaultOptions);
+        
+        return stream_context_create($options, $defaultParams);
+    }
+}

+ 1 - 1
tests/Composer/Test/Autoload/AutoloadGeneratorTest.php

@@ -13,7 +13,7 @@
 namespace Composer\Test\Installer;
 
 use Composer\Autoload\AutoloadGenerator;
-use Composer\Downloader\Util\Filesystem;
+use Composer\Util\Filesystem;
 use Composer\Package\MemoryPackage;
 
 class AutoloadGeneratorTest extends \PHPUnit_Framework_TestCase

+ 1 - 1
tests/Composer/Test/Downloader/Util/FilesystemTest.php

@@ -12,7 +12,7 @@
 
 namespace Composer\Test\Repository;
 
-use Composer\Downloader\Util\Filesystem;
+use Composer\Util\Filesystem;
 use Composer\Test\TestCase;
 
 class FilesystemTest extends TestCase

+ 1 - 1
tests/Composer/Test/Installer/LibraryInstallerTest.php

@@ -14,7 +14,7 @@ namespace Composer\Test\Installer;
 
 use Composer\Installer\LibraryInstaller;
 use Composer\DependencyResolver\Operation;
-use Composer\Downloader\Util\Filesystem;
+use Composer\Util\Filesystem;
 
 class LibraryInstallerTest extends \PHPUnit_Framework_TestCase
 {

+ 66 - 0
tests/Composer/Test/Package/Dumper/ArrayDumperTest.php

@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Test\Package\Dumper;
+
+use Composer\Package\Dumper\ArrayDumper;
+use Composer\Package\MemoryPackage;
+
+class ArrayDumperTest extends \PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        $this->dumper = new ArrayDumper();
+    }
+
+    public function testRequiredInformations()
+    {
+        $package = new MemoryPackage('foo', '1.0.0.0', '1.0');
+
+        $config = $this->dumper->dump($package);
+        $this->assertEquals(array('name', 'version', 'version_normalized', 'type', 'names'), array_keys($config));
+    }
+
+    /**
+     * @dataProvider getKeys
+     */
+    public function testKeys($key, $value, $expectedValue = null, $method = null)
+    {
+        $package = new MemoryPackage('foo', '1.0.0.0', '1.0');
+
+        $setter = 'set'.ucfirst($method ?: $key);
+        $package->$setter($value);
+
+        $config = $this->dumper->dump($package);
+        $this->assertArrayHasKey($key, $config);
+
+        $expectedValue = $expectedValue ?: $value;
+        $this->assertSame($expectedValue, $config[$key]);
+    }
+
+    public function getKeys()
+    {
+        return array(
+            array('time', new \DateTime('2012-02-01'), '2012-02-01 00:00:00', 'ReleaseDate'),
+            array('authors', array('Nils Adermann <naderman@naderman.de>', 'Jordi Boggiano <j.boggiano@seld.be>')),
+            array('homepage', 'http://getcomposer.org'),
+            array('description', 'Package Manager'),
+            array('keywords', array('package', 'dependency', 'autoload')),
+            array('bin', array('bin/composer'), null, 'binaries'),
+            array('license', array('MIT')),
+            array('autoload', array('psr-0' => array('Composer' => 'src/'))),
+            array('repositories', array('packagist' => false)),
+            array('scripts', array('post-update-cmd' => 'MyVendor\\MyClass::postUpdate')),
+            array('extra', array('class' => 'MyVendor\\Installer')),
+        );
+    }
+}

+ 0 - 2
tests/bootstrap.php

@@ -16,6 +16,4 @@ if ((!$loader = @include __DIR__.'/../../../.composer/autoload.php') && (!$loade
         'php composer.phar install'.PHP_EOL);
 }
 
-$loader = require __DIR__.'/../vendor/.composer/autoload.php';
 $loader->add('Composer\Test', __DIR__);
-$loader->register();