Installer.php 6.16 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\composer;

use Composer\Package\PackageInterface;
use Composer\Installer\LibraryInstaller;
use Composer\Repository\InstalledRepositoryInterface;
Qiang Xue committed
13
use Composer\Script\CommandEvent;
14
use Composer\Util\Filesystem;
15 16 17 18 19 20 21

/**
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Installer extends LibraryInstaller
{
Qiang Xue committed
22
	const EXTRA_BOOTSTRAP = 'bootstrap';
Qiang Xue committed
23 24
	const EXTRA_WRITABLE = 'writable';
	const EXTRA_EXECUTABLE = 'executable';
25

26 27
	const EXTENSION_FILE = 'yiisoft/extensions.php';

28
	/**
Qiang Xue committed
29
	 * @inheritdoc
30 31 32
	 */
	public function supports($packageType)
	{
33
		return $packageType === 'yii2-extension';
34 35 36
	}

	/**
Qiang Xue committed
37
	 * @inheritdoc
38 39 40
	 */
	public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
	{
41
		// install the package the normal composer way
42
		parent::install($repo, $package);
43
		// add the package to yiisoft/extensions.php
44
		$this->addPackage($package);
45 46 47 48
		// ensure the yii2-dev package also provides Yii.php in the same place as yii2 does
		if ($package->getName() == 'yiisoft/yii2-dev') {
			$this->linkYiiBaseFiles();
		}
49 50 51
	}

	/**
Qiang Xue committed
52
	 * @inheritdoc
53 54 55 56 57 58
	 */
	public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
	{
		parent::update($repo, $initial, $target);
		$this->removePackage($initial);
		$this->addPackage($target);
59
		// ensure the yii2-dev package also provides Yii.php in the same place as yii2 does
Carsten Brandt committed
60
		if ($initial->getName() == 'yiisoft/yii2-dev') {
61 62
			$this->linkYiiBaseFiles();
		}
63 64 65
	}

	/**
Qiang Xue committed
66
	 * @inheritdoc
67 68 69
	 */
	public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
	{
70
		// uninstall the package the normal composer way
71
		parent::uninstall($repo, $package);
72
		// remove the package from yiisoft/extensions.php
73
		$this->removePackage($package);
74 75 76 77
		// remove links for Yii.php
		if ($package->getName() == 'yiisoft/yii2-dev') {
			$this->removeYiiBaseFiles();
		}
78 79 80 81
	}

	protected function addPackage(PackageInterface $package)
	{
Qiang Xue committed
82
		$extension = [
83
			'name' => $package->getName(),
Qiang Xue committed
84 85
			'version' => $package->getVersion(),
		];
86

87 88 89 90
		$alias = $this->generateDefaultAlias($package);
		if (!empty($alias)) {
			$extension['alias'] = $alias;
		}
91
		$extra = $package->getExtra();
Qiang Xue committed
92 93
		if (isset($extra[self::EXTRA_BOOTSTRAP]) && is_string($extra[self::EXTRA_BOOTSTRAP])) {
			$extension['bootstrap'] = $extra[self::EXTRA_BOOTSTRAP];
94 95 96
		}

		$extensions = $this->loadExtensions();
97
		$extensions[$package->getName()] = $extension;
98 99 100
		$this->saveExtensions($extensions);
	}

101 102 103
	protected function generateDefaultAlias(PackageInterface $package)
	{
		$autoload = $package->getAutoload();
Qiang Xue committed
104 105 106 107 108
		if (empty($autoload['psr-0'])) {
			return false;
		}
		$fs = new Filesystem;
		$vendorDir = $fs->normalizePath($this->vendorDir);
Qiang Xue committed
109
		$aliases = [];
Qiang Xue committed
110 111 112 113 114 115 116
		foreach ($autoload['psr-0'] as $name => $path) {
			$name = str_replace('\\', '/', trim($name, '\\'));
			if (!$fs->isAbsolutePath($path)) {
				$path = $this->vendorDir . '/' . $package->getName() . '/' . $path;
			}
			$path = $fs->normalizePath($path);
			if (strpos($path . '/', $vendorDir . '/') === 0) {
Qiang Xue committed
117
				$aliases["@$name"] = '<vendor-dir>' . substr($path, strlen($vendorDir)) . '/' . $name;
Qiang Xue committed
118
			} else {
Qiang Xue committed
119
				$aliases["@$name"] = $path . '/' . $name;
120 121
			}
		}
Qiang Xue committed
122
		return $aliases;
123 124
	}

125 126 127
	protected function removePackage(PackageInterface $package)
	{
		$packages = $this->loadExtensions();
128
		unset($packages[$package->getName()]);
129 130 131 132 133
		$this->saveExtensions($packages);
	}

	protected function loadExtensions()
	{
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
		$file = $this->vendorDir . '/' . self::EXTENSION_FILE;
		if (!is_file($file)) {
			return [];
		}
		$extensions = require($file);

		$vendorDir = str_replace('\\', '/', $this->vendorDir);
		$n = strlen($vendorDir);

		foreach ($extensions as &$extension) {
			if (isset($extension['alias'])) {
				foreach ($extension['alias'] as $alias => $path) {
					$path = str_replace('\\', '/', $path);
					if (strpos($path . '/', $vendorDir . '/') === 0) {
						$extension['alias'][$alias] = '<vendor-dir>' . substr($path, $n);
					}
				}
			}
		}

		return $extensions;
155 156 157 158
	}

	protected function saveExtensions(array $extensions)
	{
159 160 161
		$file = $this->vendorDir . '/' . self::EXTENSION_FILE;
		$array = str_replace("'<vendor-dir>", '$vendorDir . \'', var_export($extensions, true));
		file_put_contents($file, "<?php\n\n\$vendorDir = dirname(__DIR__);\n\nreturn $array;\n");
162
	}
163

164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
	protected function linkYiiBaseFiles()
	{
		$yiiDir = $this->vendorDir . '/yiisoft/yii2/yii';
		if (!file_exists($yiiDir)) {
			mkdir($yiiDir, 0777, true);
		}
		foreach(['Yii.php', 'YiiBase.php', 'classes.php'] as $file) {
			file_put_contents($yiiDir . '/' . $file, <<<EOF
<?php
/**
* This is a link provided by the yiisoft/yii2-dev package via yii2-composer plugin.
*
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/

return require(__DIR__ . '/../../yii2-dev/framework/yii/$file');

EOF
			);
		}
	}

	protected function removeYiiBaseFiles()
	{
		$yiiDir = $this->vendorDir . '/yiisoft/yii2/yii';
		foreach(['Yii.php', 'YiiBase.php', 'classes.php'] as $file) {
			if (file_exists($yiiDir . '/' . $file)) {
				unlink($yiiDir . '/' . $file);
			}
		}
		if (file_exists($yiiDir)) {
			rmdir($yiiDir);
		}
	}
200 201

	/**
Qiang Xue committed
202
	 * Sets the correct permission for the files and directories listed in the extra section.
203 204
	 * @param CommandEvent $event
	 */
Qiang Xue committed
205
	public static function setPermission($event)
206
	{
Alexander Makarov committed
207
		$options = array_merge([
Qiang Xue committed
208 209
			self::EXTRA_WRITABLE => [],
			self::EXTRA_EXECUTABLE => [],
Alexander Makarov committed
210
		], $event->getComposer()->getPackage()->getExtra());
211

Qiang Xue committed
212
		foreach ((array)$options[self::EXTRA_WRITABLE] as $path) {
213 214 215 216 217 218 219 220 221 222
			echo "Setting writable: $path ...";
			if (is_dir($path)) {
				chmod($path, 0777);
				echo "done\n";
			} else {
				echo "The directory was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path;
				return;
			}
		}

Qiang Xue committed
223
		foreach ((array)$options[self::EXTRA_EXECUTABLE] as $path) {
224 225 226 227 228 229 230 231 232 233
			echo "Setting executable: $path ...";
			if (is_file($path)) {
				chmod($path, 0755);
				echo "done\n";
			} else {
				echo "\n\tThe file was not found: " . getcwd() . DIRECTORY_SEPARATOR . $path . "\n";
				return;
			}
		}
	}
234
}