Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / vendor / drush / drush / src / Config / Environment.php
1 <?php
2 namespace Drush\Config;
3
4 use Composer\Autoload\ClassLoader;
5
6 use Drush\Drush;
7 use Drush\Utils\FsUtils;
8 use Webmozart\PathUtil\Path;
9
10 /**
11  * Store information about the environment
12  */
13 class Environment
14 {
15     protected $homeDir;
16     protected $originalCwd;
17     protected $etcPrefix;
18     protected $sharePrefix;
19     protected $drushBasePath;
20     protected $vendorDir;
21
22     protected $docPrefix;
23     protected $configFileVariant;
24
25     protected $loader;
26     protected $siteLoader;
27
28     /**
29      * Environment constructor
30      * @param string $homeDir User home directory.
31      * @param string $cwd The current working directory at the time Drush was called.
32      * @param string $autoloadFile Path to the autoload.php file.
33      */
34     public function __construct($homeDir, $cwd, $autoloadFile)
35     {
36         $this->homeDir = $homeDir;
37         $this->originalCwd = Path::canonicalize($cwd);
38         $this->etcPrefix = '';
39         $this->sharePrefix = '';
40         $this->drushBasePath = dirname(dirname(__DIR__));
41         $this->vendorDir = FsUtils::realpath(dirname($autoloadFile));
42     }
43
44     /**
45      * Load the autoloader for the selected Drupal site
46      *
47      * @param string $root
48      * @return ClassLoader
49      */
50     public function loadSiteAutoloader($root)
51     {
52         $autloadFilePath = "$root/autoload.php";
53         if (!file_exists($autloadFilePath)) {
54             return $this->loader;
55         }
56
57         if ($this->siteLoader) {
58             return $this->siteLoader;
59         }
60
61         $this->siteLoader = require $autloadFilePath;
62         if ($this->siteLoader === true) {
63             // The autoloader was already required. Assume that Drush and Drupal share an autoloader per
64             // "Point autoload.php to the proper vendor directory" - https://www.drupal.org/node/2404989
65             $this->siteLoader = $this->loader;
66         }
67
68         // Ensure that the site's autoloader has highest priority. Usually,
69         // the first classloader registered gets the first shot at loading classes.
70         // We want Drupal's classloader to be used first when a class is loaded,
71         // and have Drush's classloader only be called as a fallback measure.
72         $this->siteLoader->unregister();
73         $this->siteLoader->register(true);
74
75         return $this->siteLoader;
76     }
77
78     /**
79      * Return the name of the user running drush.
80      *
81      * @return string
82      */
83     protected function getUsername()
84     {
85         $name = null;
86         if (!$name = getenv("username")) { // Windows
87             if (!$name = getenv("USER")) {
88                 // If USER not defined, use posix
89                 if (function_exists('posix_getpwuid')) {
90                     $processUser = posix_getpwuid(posix_geteuid());
91                     $name = $processUser['name'];
92                 }
93             }
94         }
95         return $name;
96     }
97
98     protected function getTmp()
99     {
100         $directories = [];
101
102         // Get user specific and operating system temp folders from system environment variables.
103         // See http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/ntcmds_shelloverview.mspx?mfr=true
104         $tempdir = getenv('TEMP');
105         if (!empty($tempdir)) {
106             $directories[] = $tempdir;
107         }
108         $tmpdir = getenv('TMP');
109         if (!empty($tmpdir)) {
110             $directories[] = $tmpdir;
111         }
112         // Operating system specific dirs.
113         if (self::isWindows()) {
114             $windir = getenv('WINDIR');
115             if (isset($windir)) {
116                 // WINDIR itself is not writable, but it always contains a /Temp dir,
117                 // which is the system-wide temporary directory on older versions. Newer
118                 // versions only allow system processes to use it.
119                 $directories[] = Path::join($windir, 'Temp');
120             }
121         } else {
122             $directories[] = Path::canonicalize('/tmp');
123         }
124         $directories[] = Path::canonicalize(sys_get_temp_dir());
125
126         foreach ($directories as $directory) {
127             if (is_dir($directory) && is_writable($directory)) {
128                 $temporary_directory = $directory;
129                 break;
130             }
131         }
132
133         if (empty($temporary_directory)) {
134             // If no directory has been found, create one in cwd.
135             $temporary_directory = Path::join(Drush::config()->cwd(), 'tmp');
136             drush_mkdir($temporary_directory, true);
137             if (!is_dir($temporary_directory)) {
138                 throw new \Exception(dt("Unable to create a temporary directory."));
139             }
140             // Function not available yet - this is not likely to get reached anyway.
141             // drush_register_file_for_deletion($temporary_directory);
142         }
143         return $temporary_directory;
144     }
145
146     /**
147      * Convert the environment object into an exported configuration
148      * array.
149      *
150      * @see PreflightArgs::applyToConfig(), which also exports information to config.
151      *
152      * @return array Nested associative array that is overlayed on configuration.
153      */
154     public function exportConfigData()
155     {
156         return [
157             // Information about the environment presented to Drush
158             'env' => [
159                 'cwd' => $this->cwd(),
160                 'home' => $this->homeDir(),
161                 'user' => $this->getUsername(),
162                 'is-windows' => $this->isWindows(),
163                 'tmp' => $this->getTmp(),
164             ],
165             // These values are available as global options, and
166             // will be passed in to the FormatterOptions et. al.
167             'options' => [
168                 'width' => $this->calculateColumns(),
169             ],
170             // Information about the directories where Drush found assets, etc.
171             'drush' => [
172                 'base-dir' => $this->drushBasePath,
173                 'vendor-dir' => $this->vendorPath(),
174                 'docs-dir' => $this->docsPath(),
175                 'user-dir' => $this->userConfigPath(),
176                 'system-dir' => $this->systemConfigPath(),
177                 'system-command-dir' => $this->systemCommandFilePath(),
178             ],
179             'runtime' => [
180                 'site-file-previous' => $this->getSiteSetAliasFilePath('drush-drupal-prev-site-'),
181                 'site-file-current' => $this->getSiteSetAliasFilePath(),
182             ],
183         ];
184     }
185
186     /**
187      * The base directory of the Drush application itself
188      * (where composer.json et.al. are found)
189      *
190      * @return string
191      */
192     public function drushBasePath()
193     {
194         return $this->drushBasePath;
195     }
196
197     /**
198      * Get the site:set alias from the current site:set file path.
199      *
200      * @return bool|string
201      */
202     public function getSiteSetAliasName()
203     {
204         $site_filename = $this->getSiteSetAliasFilePath();
205         if (file_exists($site_filename)) {
206             $site = file_get_contents($site_filename);
207             if ($site) {
208                 return $site;
209             }
210         }
211         return false;
212     }
213
214     /**
215      * User's home directory
216      *
217      * @return string
218      */
219     public function homeDir()
220     {
221         return $this->homeDir;
222     }
223
224     /**
225      * The user's Drush configuration directory, ~/.drush
226      *
227      * @return string
228      */
229     public function userConfigPath()
230     {
231         return $this->homeDir() . '/.drush';
232     }
233
234     public function setConfigFileVariant($variant)
235     {
236         $this->configFileVariant = $variant;
237     }
238
239     /**
240      * Get the config file variant -- defined to be
241      * the Drush major version number. This is for
242      * loading drush.yml and drush9.yml, etc.
243      */
244     public function getConfigFileVariant()
245     {
246         return $this->configFileVariant;
247     }
248
249     /**
250      * The original working directory
251      *
252      * @return string
253      */
254     public function cwd()
255     {
256         return $this->originalCwd;
257     }
258
259     /**
260      * Return the path to Drush's vendor directory
261      *
262      * @return string
263      */
264     public function vendorPath()
265     {
266         return $this->vendorDir;
267     }
268
269     /**
270      * The class loader returned when the autoload.php file is included.
271      *
272      * @return \Composer\Autoload\ClassLoader
273      */
274     public function loader()
275     {
276         return $this->loader;
277     }
278
279     /**
280      * Set the class loader from the autload.php file, if available.
281      *
282      * @param \Composer\Autoload\ClassLoader $loader
283      */
284     public function setLoader(ClassLoader $loader)
285     {
286         $this->loader = $loader;
287     }
288
289     /**
290      * Alter our default locations based on the value of environment variables
291      *
292      * @return $this
293      */
294     public function applyEnvironment()
295     {
296         // Copy ETC_PREFIX and SHARE_PREFIX from environment variables if available.
297         // This alters where we check for server-wide config and alias files.
298         // Used by unit test suite to provide a clean environment.
299         $this->setEtcPrefix(getenv('ETC_PREFIX'));
300         $this->setSharePrefix(getenv('SHARE_PREFIX'));
301
302         return $this;
303     }
304
305     /**
306      * Set the directory prefix to locate the directory that Drush will
307      * use as /etc (e.g. during the functional tests)
308      *
309      * @param string $etcPrefix
310      * @return $this
311      */
312     public function setEtcPrefix($etcPrefix)
313     {
314         if (isset($etcPrefix)) {
315             $this->etcPrefix = $etcPrefix;
316         }
317         return $this;
318     }
319
320     /**
321      * Set the directory prefix to locate the directory that Drush will
322      * use as /user/share (e.g. during the functional tests)
323      * @param string $sharePrefix
324      * @return $this
325      */
326     public function setSharePrefix($sharePrefix)
327     {
328         if (isset($sharePrefix)) {
329             $this->sharePrefix = $sharePrefix;
330             $this->docPrefix = null;
331         }
332         return $this;
333     }
334
335     /**
336      * Return the directory where Drush's documentation is stored. Usually
337      * this is within the Drush application, but some Drush RPM distributions
338      * & c. for Linux platforms slice-and-dice the contents and put the docs
339      * elsewhere.
340      *
341      * @return string
342      */
343     public function docsPath()
344     {
345         if (!$this->docPrefix) {
346             $this->docPrefix = $this->findDocsPath($this->drushBasePath);
347         }
348         return $this->docPrefix;
349     }
350
351     /**
352      * Locate the Drush documentation. This is recalculated whenever the
353      * share prefix is changed.
354      *
355      * @param string $drushBasePath
356      * @return string
357      */
358     protected function findDocsPath($drushBasePath)
359     {
360         $candidates = [
361             "$drushBasePath/README.md",
362             static::systemPathPrefix($this->sharePrefix, '/usr') . '/share/docs/drush/README.md',
363         ];
364         return $this->findFromCandidates($candidates);
365     }
366
367     /**
368      * Check a list of directories and return the first one that exists.
369      *
370      * @param array $candidates
371      * @return string|boolean
372      */
373     protected function findFromCandidates($candidates)
374     {
375         foreach ($candidates as $candidate) {
376             if (file_exists($candidate)) {
377                 return dirname($candidate);
378             }
379         }
380         return false;
381     }
382
383     /**
384      * Return the appropriate system path prefix, unless an override is provided.
385      * @param string $override
386      * @param string $defaultPrefix
387      * @return string
388      */
389     protected static function systemPathPrefix($override = '', $defaultPrefix = '')
390     {
391         if ($override) {
392             return $override;
393         }
394         return static::isWindows() ? getenv('ALLUSERSPROFILE') . '/Drush' : $defaultPrefix;
395     }
396
397     /**
398      * Return the system configuration path (default: /etc/drush)
399      *
400      * @return string
401      */
402     public function systemConfigPath()
403     {
404         return static::systemPathPrefix($this->etcPrefix, '') . '/etc/drush';
405     }
406
407     /**
408      * Return the system shared commandfile path (default: /usr/share/drush/commands)
409      *
410      * @return string
411      */
412     public function systemCommandFilePath()
413     {
414         return static::systemPathPrefix($this->sharePrefix, '/usr') . '/share/drush/commands';
415     }
416
417     /**
418      * Determine whether current OS is a Windows variant.
419      *
420      * @return boolean
421      */
422     public static function isWindows($os = null)
423     {
424         return strtoupper(substr($os ?: PHP_OS, 0, 3)) === 'WIN';
425     }
426
427     /**
428      * Verify that we are running PHP through the command line interface.
429      *
430      * @return boolean
431      *   A boolean value that is true when PHP is being run through the command line,
432      *   and false if being run through cgi or mod_php.
433      */
434     public function verifyCLI()
435     {
436         return (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0));
437     }
438
439     /**
440      * Calculate the terminal width used for wrapping table output.
441      * Normally this is exported using tput in the drush script.
442      * If this is not present we do an additional check using stty here.
443      * On Windows in CMD and PowerShell is this exported using mode con.
444      *
445      * @return integer
446      */
447     public function calculateColumns()
448     {
449         if ($columns = getenv('COLUMNS')) {
450             return $columns;
451         }
452
453         // Trying to export the columns using stty.
454         exec('stty size 2>&1', $columns_output, $columns_status);
455         if (!$columns_status) {
456             $columns = preg_replace('/\d+\s(\d+)/', '$1', $columns_output[0], -1, $columns_count);
457         }
458
459         // If stty fails and Drush us running on Windows are we trying with mode con.
460         if (($columns_status || !$columns_count) && static::isWindows()) {
461             $columns_output = [];
462             exec('mode con', $columns_output, $columns_status);
463             if (!$columns_status && is_array($columns_output)) {
464                 $columns = (int)preg_replace('/\D/', '', $columns_output[4], -1, $columns_count);
465             }
466             // TODO: else { 'Drush could not detect the console window width. Set a Windows Environment Variable of COLUMNS to the desired width.'
467         }
468
469         // Failling back to default columns value
470         if (empty($columns)) {
471             $columns = 80;
472         }
473
474         // TODO: should we deal with reserve-margin here, or adjust it later?
475         return $columns;
476     }
477
478     /**
479      * Returns the filename for the file that stores the DRUPAL_SITE variable.
480      *
481      * @param string $filename_prefix
482      *   An arbitrary string to prefix the filename with.
483      *
484      * @return string|false
485      *   Returns the full path to temp file if possible, or FALSE if not.
486      */
487     protected function getSiteSetAliasFilePath($filename_prefix = 'drush-drupal-site-')
488     {
489         $shell_pid = getenv('DRUSH_SHELL_PID');
490         if (!$shell_pid && function_exists('posix_getppid')) {
491             $shell_pid = posix_getppid();
492         }
493         if (!$shell_pid) {
494             return false;
495         }
496
497         // The env variables below must match the variables in example.prompt.sh
498         $tmp = getenv('TMPDIR') ? getenv('TMPDIR') : '/tmp';
499         $username = $this->getUsername();
500
501         return "{$tmp}/drush-env-{$username}/{$filename_prefix}" . $shell_pid;
502     }
503 }