Browse Source

Merge pull request #572 from Seldaek/install-notifications

Add repository notification API support
Nils Adermann 13 năm trước cách đây
mục cha
commit
5269bfa25c

+ 1 - 0
CHANGELOG.md

@@ -2,6 +2,7 @@
 
 
   * Added caching of repository metadata (faster startup times & failover if packagist is down)
   * Added caching of repository metadata (faster startup times & failover if packagist is down)
   * Added include_path support for legacy projects that are full of require_once statements
   * Added include_path support for legacy projects that are full of require_once statements
+  * Added installation notifications API to allow better statistics on Composer repositories
   * Improved repository protocol to have large cacheable parts
   * Improved repository protocol to have large cacheable parts
 
 
 * 1.0.0-alpha2 (2012-04-03)
 * 1.0.0-alpha2 (2012-04-03)

+ 1 - 0
src/Composer/Config.php

@@ -26,6 +26,7 @@ class Config
             'process-timeout' => 300,
             'process-timeout' => 300,
             'vendor-dir' => 'vendor',
             'vendor-dir' => 'vendor',
             'bin-dir' => '{$vendor-dir}/bin',
             'bin-dir' => '{$vendor-dir}/bin',
+            'notify-on-install' => true,
         );
         );
     }
     }
 
 

+ 10 - 0
src/Composer/Installer/InstallationManager.php

@@ -14,6 +14,7 @@ namespace Composer\Installer;
 
 
 use Composer\Package\PackageInterface;
 use Composer\Package\PackageInterface;
 use Composer\Package\AliasPackage;
 use Composer\Package\AliasPackage;
+use Composer\Repository\NotifiableRepositoryInterface;
 use Composer\DependencyResolver\Operation\OperationInterface;
 use Composer\DependencyResolver\Operation\OperationInterface;
 use Composer\DependencyResolver\Operation\InstallOperation;
 use Composer\DependencyResolver\Operation\InstallOperation;
 use Composer\DependencyResolver\Operation\UpdateOperation;
 use Composer\DependencyResolver\Operation\UpdateOperation;
@@ -128,6 +129,7 @@ class InstallationManager
         }
         }
         $installer = $this->getInstaller($package->getType());
         $installer = $this->getInstaller($package->getType());
         $installer->install($package);
         $installer->install($package);
+        $this->notifyInstall($package);
     }
     }
 
 
     /**
     /**
@@ -153,6 +155,7 @@ class InstallationManager
         if ($initialType === $targetType) {
         if ($initialType === $targetType) {
             $installer = $this->getInstaller($initialType);
             $installer = $this->getInstaller($initialType);
             $installer->update($initial, $target);
             $installer->update($initial, $target);
+            $this->notifyInstall($target);
         } else {
         } else {
             $this->getInstaller($initialType)->uninstall($initial);
             $this->getInstaller($initialType)->uninstall($initial);
             $this->getInstaller($targetType)->install($target);
             $this->getInstaller($targetType)->install($target);
@@ -200,4 +203,11 @@ class InstallationManager
 
 
         return getcwd().DIRECTORY_SEPARATOR.$this->vendorPath;
         return getcwd().DIRECTORY_SEPARATOR.$this->vendorPath;
     }
     }
+
+    protected function notifyInstall(PackageInterface $package)
+    {
+        if ($package->getRepository() instanceof NotifiableRepositoryInterface) {
+            $package->getRepository()->notifyInstall($package);
+        }
+    }
 }
 }

+ 39 - 1
src/Composer/Repository/ComposerRepository.php

@@ -14,6 +14,7 @@ namespace Composer\Repository;
 
 
 use Composer\Package\Loader\ArrayLoader;
 use Composer\Package\Loader\ArrayLoader;
 use Composer\Package\LinkConstraint\VersionConstraint;
 use Composer\Package\LinkConstraint\VersionConstraint;
+use Composer\Package\PackageInterface;
 use Composer\Json\JsonFile;
 use Composer\Json\JsonFile;
 use Composer\Cache;
 use Composer\Cache;
 use Composer\Config;
 use Composer\Config;
@@ -23,12 +24,14 @@ use Composer\Util\RemoteFilesystem;
 /**
 /**
  * @author Jordi Boggiano <j.boggiano@seld.be>
  * @author Jordi Boggiano <j.boggiano@seld.be>
  */
  */
-class ComposerRepository extends ArrayRepository
+class ComposerRepository extends ArrayRepository implements NotifiableRepositoryInterface
 {
 {
+    protected $config;
     protected $url;
     protected $url;
     protected $io;
     protected $io;
     protected $packages;
     protected $packages;
     protected $cache;
     protected $cache;
+    protected $notifyUrl;
 
 
     public function __construct(array $repoConfig, IOInterface $io, Config $config)
     public function __construct(array $repoConfig, IOInterface $io, Config $config)
     {
     {
@@ -41,11 +44,41 @@ class ComposerRepository extends ArrayRepository
             throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
             throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
         }
         }
 
 
+        $this->config = $config;
         $this->url = $repoConfig['url'];
         $this->url = $repoConfig['url'];
         $this->io = $io;
         $this->io = $io;
         $this->cache = new Cache($io, $config->get('home').'/cache/'.preg_replace('{[^a-z0-9.]}', '-', $this->url));
         $this->cache = new Cache($io, $config->get('home').'/cache/'.preg_replace('{[^a-z0-9.]}', '-', $this->url));
     }
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
+    public function notifyInstall(PackageInterface $package)
+    {
+        if (!$this->notifyUrl || !$this->config->get('notify-on-install')) {
+            return;
+        }
+
+        // TODO use an optional curl_multi pool for all the notifications
+        $url = str_replace('%package%', $package->getPrettyName(), $this->notifyUrl);
+
+        $params = array(
+            'version' => $package->getPrettyVersion(),
+            'version_normalized' => $package->getVersion(),
+        );
+        $opts = array('http' =>
+            array(
+                'method'  => 'POST',
+                'header'  => 'Content-type: application/x-www-form-urlencoded',
+                'content' => http_build_query($params),
+                'timeout' => 3,
+            )
+        );
+
+        $context = stream_context_create($opts);
+        @file_get_contents($url, false, $context);
+    }
+
     protected function initialize()
     protected function initialize()
     {
     {
         parent::initialize();
         parent::initialize();
@@ -53,6 +86,11 @@ class ComposerRepository extends ArrayRepository
         try {
         try {
             $json = new JsonFile($this->url.'/packages.json', new RemoteFilesystem($this->io));
             $json = new JsonFile($this->url.'/packages.json', new RemoteFilesystem($this->io));
             $data = $json->read();
             $data = $json->read();
+
+            if (!empty($data['notify'])) {
+                $this->notifyUrl = preg_replace('{(https?://[^/]+).*}i', '$1' . $data['notify'], $this->url);
+            }
+
             $this->cache->write('packages.json', json_encode($data));
             $this->cache->write('packages.json', json_encode($data));
         } catch (\Exception $e) {
         } catch (\Exception $e) {
             if ($contents = $this->cache->read('packages.json')) {
             if ($contents = $this->cache->read('packages.json')) {

+ 28 - 0
src/Composer/Repository/NotifiableRepositoryInterface.php

@@ -0,0 +1,28 @@
+<?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\Repository;
+
+use Composer\Package\PackageInterface;
+
+/**
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+interface NotifiableRepositoryInterface extends RepositoryInterface
+{
+    /**
+     * Notify this repository about the installation of a package
+     *
+     * @param PackageInterface $package Package that is installed
+     */
+    function notifyInstall(PackageInterface $package);
+}