1<?php 2 3/* 4 * This file is part of Component Installer. 5 * 6 * (c) Rob Loach (http://robloach.net) 7 * 8 * For the full copyright and license information, please view the LICENSE.md 9 * file that was distributed with this source code. 10 */ 11 12namespace ComponentInstaller; 13 14use Composer\Composer; 15use Composer\Installer\LibraryInstaller; 16use Composer\Script\Event; 17use Composer\Package\PackageInterface; 18use Composer\Package\AliasPackage; 19use Composer\Util\Filesystem; 20 21/** 22 * Component Installer for Composer. 23 */ 24class Installer extends LibraryInstaller 25{ 26 27 /** 28 * The location where Components are to be installed. 29 */ 30 protected $componentDir; 31 32 /** 33 * {@inheritDoc} 34 * 35 * Components are supported by all packages. This checks wheteher or not the 36 * entire package is a "component", as well as injects the script to act 37 * on components embedded in packages that are not just "component" types. 38 */ 39 public function supports($packageType) 40 { 41 // Components are supported by all package types. We will just act on 42 // the root package's scripts if available. 43 $rootPackage = isset($this->composer) ? $this->composer->getPackage() : null; 44 if (isset($rootPackage)) { 45 // Ensure we get the root package rather than its alias. 46 while ($rootPackage instanceof AliasPackage) { 47 $rootPackage = $rootPackage->getAliasOf(); 48 } 49 50 // Make sure the root package can override the available scripts. 51 if (method_exists($rootPackage, 'setScripts')) { 52 $scripts = $rootPackage->getScripts(); 53 // Act on the "post-autoload-dump" command so that we can act on all 54 // the installed packages. 55 $scripts['post-autoload-dump']['component-installer'] = 'ComponentInstaller\\Installer::postAutoloadDump'; 56 $rootPackage->setScripts($scripts); 57 } 58 } 59 60 // Explicitly state support of "component" packages. 61 return $packageType === 'component'; 62 } 63 64 /** 65 * Gets the destination Component directory. 66 * 67 * @return string 68 * The path to where the final Component should be installed. 69 */ 70 public function getComponentPath(PackageInterface $package) 71 { 72 // Parse the pretty name for the vendor and package name. 73 $name = $prettyName = $package->getPrettyName(); 74 if (strpos($prettyName, '/') !== false) { 75 list($vendor, $name) = explode('/', $prettyName); 76 } 77 78 // Allow the component to define its own name. 79 $extra = $package->getExtra(); 80 $component = isset($extra['component']) ? $extra['component'] : array(); 81 if (isset($component['name'])) { 82 $name = $component['name']; 83 } 84 85 // Find where the package should be located. 86 return $this->getComponentDir() . DIRECTORY_SEPARATOR . $name; 87 } 88 89 /** 90 * Initialize the Component directory, as well as the vendor directory. 91 */ 92 protected function initializeVendorDir() 93 { 94 $this->componentDir = $this->getComponentDir(); 95 $this->filesystem->ensureDirectoryExists($this->componentDir); 96 return parent::initializeVendorDir(); 97 } 98 99 /** 100 * Retrieves the Installer's provided component directory. 101 */ 102 public function getComponentDir() 103 { 104 $config = $this->composer->getConfig(); 105 return $config->has('component-dir') ? $config->get('component-dir') : 'components'; 106 } 107 108 /** 109 * Remove both the installed code and files from the Component directory. 110 */ 111 public function removeCode(PackageInterface $package) 112 { 113 $this->removeComponent($package); 114 return parent::removeCode($package); 115 } 116 117 /** 118 * Remove a Component's files from the Component directory. 119 */ 120 public function removeComponent(PackageInterface $package) 121 { 122 $path = $this->getComponentPath($package); 123 return $this->filesystem->remove($path); 124 } 125 126 /** 127 * Before installing the Component, be sure its destination is clear first. 128 */ 129 public function installCode(PackageInterface $package) 130 { 131 $this->removeComponent($package); 132 return parent::installCode($package); 133 } 134 135 /** 136 * Script callback; Acted on after the autoloader is dumped. 137 */ 138 public static function postAutoloadDump(Event $event) 139 { 140 // Retrieve basic information about the environment and present a 141 // message to the user. 142 $composer = $event->getComposer(); 143 $io = $event->getIO(); 144 $io->write('<info>Compiling component files</info>'); 145 146 // Set up all the processes. 147 $processes = array( 148 // Copy the assets to the Components directory. 149 "ComponentInstaller\\Process\\CopyProcess", 150 // Build the require.js file. 151 "ComponentInstaller\\Process\\RequireJsProcess", 152 // Build the require.css file. 153 "ComponentInstaller\\Process\\RequireCssProcess", 154 // Compile the require-built.js file. 155 "ComponentInstaller\\Process\\BuildJsProcess", 156 ); 157 158 // Initialize and execute each process in sequence. 159 foreach ($processes as $class) { 160 $process = new $class($composer, $io); 161 // When an error occurs during initialization, end the process. 162 if (!$process->init()) { 163 $io->write('<error>An error occurred while initializing the process.</info>'); 164 break; 165 } 166 $process->process(); 167 } 168 } 169} 170