Yaffs site version 1.1
[yaffs-website] / vendor / drupal-composer / drupal-scaffold / src / Handler.php
1 <?php
2
3 /**
4  * @file
5  * Contains \DrupalComposer\DrupalScaffold\Handler.
6  */
7
8 namespace DrupalComposer\DrupalScaffold;
9
10 use Composer\Composer;
11 use Composer\DependencyResolver\Operation\InstallOperation;
12 use Composer\DependencyResolver\Operation\UpdateOperation;
13 use Composer\EventDispatcher\EventDispatcher;
14 use Composer\IO\IOInterface;
15 use Composer\Package\PackageInterface;
16 use Composer\Util\Filesystem;
17 use Composer\Util\RemoteFilesystem;
18 use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
19
20 class Handler {
21
22   const PRE_DRUPAL_SCAFFOLD_CMD = 'pre-drupal-scaffold-cmd';
23   const POST_DRUPAL_SCAFFOLD_CMD = 'post-drupal-scaffold-cmd';
24
25   /**
26    * @var \Composer\Composer
27    */
28   protected $composer;
29
30   /**
31    * @var \Composer\IO\IOInterface
32    */
33   protected $io;
34
35   /**
36    * @var \Composer\Package\PackageInterface
37    */
38   protected $drupalCorePackage;
39
40   /**
41    * Handler constructor.
42    *
43    * @param Composer $composer
44    * @param IOInterface $io
45    */
46   public function __construct(Composer $composer, IOInterface $io) {
47     $this->composer = $composer;
48     $this->io = $io;
49   }
50
51   /**
52    * @param $operation
53    * @return mixed
54    */
55   protected function getCorePackage($operation) {
56     if ($operation instanceof InstallOperation) {
57       $package = $operation->getPackage();
58     }
59     elseif ($operation instanceof UpdateOperation) {
60       $package = $operation->getTargetPackage();
61     }
62     if (isset($package) && $package instanceof PackageInterface && $package->getName() == 'drupal/core') {
63       return $package;
64     }
65     return NULL;
66   }
67
68   /**
69    * Marks scaffolding to be processed after an install or update command.
70    *
71    * @param \Composer\Installer\PackageEvent $event
72    */
73   public function onPostPackageEvent(\Composer\Installer\PackageEvent $event){
74     $package = $this->getCorePackage($event->getOperation());
75     if ($package) {
76       // By explicitly setting the core package, the onPostCmdEvent() will
77       // process the scaffolding automatically.
78       $this->drupalCorePackage = $package;
79     }
80   }
81
82   /**
83    * Post install command event to execute the scaffolding.
84    *
85    * @param \Composer\Script\Event $event
86    */
87   public function onPostCmdEvent(\Composer\Script\Event $event) {
88     // Only install the scaffolding if drupal/core was installed,
89     // AND there are no scaffolding files present.
90     if (isset($this->drupalCorePackage)) {
91       $this->downloadScaffold();
92       // Generate the autoload.php file after generating the scaffold files.
93       $this->generateAutoload();
94     }
95   }
96
97   /**
98    * Downloads drupal scaffold files for the current process.
99    */
100   public function downloadScaffold() {
101     $drupalCorePackage = $this->getDrupalCorePackage();
102     $webroot = realpath($this->getWebRoot());
103
104     // Collect options, excludes and settings files.
105     $options = $this->getOptions();
106     $files = array_diff($this->getIncludes(), $this->getExcludes());
107
108     // Call any pre-scaffold scripts that may be defined.
109     $dispatcher = new EventDispatcher($this->composer, $this->io);
110     $dispatcher->dispatch(self::PRE_DRUPAL_SCAFFOLD_CMD);
111
112     $version = $this->getDrupalCoreVersion($drupalCorePackage);
113
114     $remoteFs = new RemoteFilesystem($this->io);
115
116     $fetcher = new PrestissimoFileFetcher($remoteFs, $options['source'], $files, $this->io, $this->composer->getConfig());
117     $fetcher->fetch($version, $webroot);
118
119     $initialFileFetcher = new InitialFileFetcher($remoteFs, $options['source'], $this->getInitial());
120     $initialFileFetcher->fetch($version, $webroot);
121
122     // Call post-scaffold scripts.
123     $dispatcher->dispatch(self::POST_DRUPAL_SCAFFOLD_CMD);
124   }
125
126   /**
127    * Generate the autoload file at the project root.  Include the
128    * autoload file that Composer generated.
129    */
130   public function generateAutoload() {
131     $vendorPath = $this->getVendorPath();
132     $webroot = $this->getWebRoot();
133
134     // Calculate the relative path from the webroot (location of the
135     // project autoload.php) to the vendor directory.
136     $fs = new SymfonyFilesystem();
137     $relativeVendorPath = $fs->makePathRelative($vendorPath, realpath($webroot));
138
139     $fs->dumpFile($webroot . "/autoload.php", $this->autoLoadContents($relativeVendorPath));
140   }
141
142   /**
143    * Build the contents of the autoload file.
144    *
145    * @return string
146    */
147   protected function autoLoadContents($relativeVendorPath) {
148     $relativeVendorPath = rtrim($relativeVendorPath, '/');
149
150     $autoloadContents = <<<EOF
151 <?php
152
153 /**
154  * @file
155  * Includes the autoloader created by Composer.
156  *
157  * This file was generated by drupal-composer/drupal-scaffold.
158  * https://github.com/drupal-composer/drupal-scaffold
159  *
160  * @see composer.json
161  * @see index.php
162  * @see core/install.php
163  * @see core/rebuild.php
164  * @see core/modules/statistics/statistics.php
165  */
166
167 return require __DIR__ . '/$relativeVendorPath/autoload.php';
168
169 EOF;
170     return $autoloadContents;
171   }
172
173   /**
174    * Get the path to the 'vendor' directory.
175    *
176    * @return string
177    */
178   public function getVendorPath() {
179     $config = $this->composer->getConfig();
180     $filesystem = new Filesystem();
181     $filesystem->ensureDirectoryExists($config->get('vendor-dir'));
182     $vendorPath = $filesystem->normalizePath(realpath($config->get('vendor-dir')));
183
184     return $vendorPath;
185   }
186
187   /**
188    * Look up the Drupal core package object, or return it from where we cached
189    * it in the $drupalCorePackage field.
190    *
191    * @return PackageInterface
192    */
193   public function getDrupalCorePackage() {
194     if (!isset($this->drupalCorePackage)) {
195       $this->drupalCorePackage = $this->getPackage('drupal/core');
196     }
197     return $this->drupalCorePackage;
198   }
199
200   /**
201    * Returns the Drupal core version for the given package.
202    *
203    * @param \Composer\Package\PackageInterface $drupalCorePackage
204    *
205    * @return string
206    */
207   protected function getDrupalCoreVersion(PackageInterface $drupalCorePackage) {
208     $version = $drupalCorePackage->getPrettyVersion();
209     if ($drupalCorePackage->getStability() == 'dev' && substr($version, -4) == '-dev') {
210       $version = substr($version, 0, -4);
211       return $version;
212     }
213     return $version;
214   }
215
216   /**
217    * Retrieve the path to the web root.
218    *
219    *  @return string
220    */
221   public function getWebRoot() {
222     $drupalCorePackage = $this->getDrupalCorePackage();
223     $installationManager = $this->composer->getInstallationManager();
224     $corePath = $installationManager->getInstallPath($drupalCorePackage);
225     // Webroot is the parent path of the drupal core installation path.
226     $webroot = dirname($corePath);
227
228     return $webroot;
229   }
230
231   /**
232    * Retrieve a package from the current composer process.
233    *
234    * @param string $name
235    *   Name of the package to get from the current composer installation.
236    *
237    * @return PackageInterface
238    */
239   protected function getPackage($name) {
240     return $this->composer->getRepositoryManager()->getLocalRepository()->findPackage($name, '*');
241   }
242
243   /**
244    * Retrieve excludes from optional "extra" configuration.
245    *
246    * @return array
247    */
248   protected function getExcludes() {
249     return $this->getNamedOptionList('excludes', 'getExcludesDefault');
250   }
251
252   /**
253    * Retrieve list of additional settings files from optional "extra" configuration.
254    *
255    * @return array
256    */
257   protected function getIncludes() {
258     return $this->getNamedOptionList('includes', 'getIncludesDefault');
259   }
260
261   /**
262    * Retrieve list of initial files from optional "extra" configuration.
263    *
264    * @return array
265    */
266   protected function getInitial() {
267     return $this->getNamedOptionList('initial', 'getInitialDefault');
268   }
269
270   /**
271    * Retrieve a named list of options from optional "extra" configuration.
272    * Respects 'omit-defaults', and either includes or does not include the
273    * default values, as requested.
274    *
275    * @return array
276    */
277   protected function getNamedOptionList($optionName, $defaultFn) {
278     $options = $this->getOptions($this->composer);
279     $result = array();
280     if (empty($options['omit-defaults'])) {
281       $result = $this->$defaultFn();
282     }
283     $result = array_merge($result, (array) $options[$optionName]);
284
285     return $result;
286   }
287
288   /**
289    * Retrieve excludes from optional "extra" configuration.
290    *
291    * @return array
292    */
293   protected function getOptions() {
294     $extra = $this->composer->getPackage()->getExtra() + ['drupal-scaffold' => []];
295     $options = $extra['drupal-scaffold'] + [
296       'omit-defaults' => FALSE,
297       'excludes' => [],
298       'includes' => [],
299       'initial' => [],
300       'source' => 'http://cgit.drupalcode.org/drupal/plain/{path}?h={version}',
301       // Github: https://raw.githubusercontent.com/drupal/drupal/{version}/{path}
302     ];
303     return $options;
304   }
305
306   /**
307    * Holds default excludes.
308    */
309   protected function getExcludesDefault() {
310     return [];
311   }
312
313   /**
314    * Holds default settings files list.
315    */
316   protected function getIncludesDefault() {
317     $version = $this->getDrupalCoreVersion($this->getDrupalCorePackage());
318     list($major, $minor) = explode('.', $version, 3);
319     $version = "$major.$minor";
320
321     /**
322      * Files from 8.3.x
323      *
324      * @see http://cgit.drupalcode.org/drupal/tree/?h=8.3.x
325      */
326     $common = [
327       '.csslintrc',
328       '.editorconfig',
329       '.eslintignore',
330       '.eslintrc.json',
331       '.gitattributes',
332       '.htaccess',
333       'index.php',
334       'robots.txt',
335       'sites/default/default.settings.php',
336       'sites/default/default.services.yml',
337       'sites/development.services.yml',
338       'sites/example.settings.local.php',
339       'sites/example.sites.php',
340       'update.php',
341       'web.config'
342     ];
343
344     // Version specific variations.
345     switch ($version) {
346       case '8.0':
347       case '8.1':
348       case '8.2':
349         $common[] = '.eslintrc';
350         $common = array_diff($common, ['.eslintrc.json']);
351         break;
352     }
353
354     sort($common);
355     return $common;
356   }
357
358   /**
359    * Holds default initial files.
360    */
361   protected function getInitialDefault() {
362     return [];
363   }
364
365 }