9 use Consolidation\SiteAlias\SiteAliasManager;
10 use League\Container\ContainerInterface;
11 use Psr\Log\LoggerInterface;
12 use Symfony\Component\Console\Application;
13 use Symfony\Component\Console\Input\InputInterface;
14 use Symfony\Component\Console\Output\OutputInterface;
16 // TODO: Not sure if we should have a reference to PreflightArgs here.
17 // Maybe these constants should be in config, and PreflightArgs can
18 // reference them from there as well.
19 use Drush\Preflight\PreflightArgs;
22 * Static Service Container wrapper.
24 * This code is analogous to the \Drupal class in Drupal 8.
26 * We would like to move Drush towards the model of using constructor
27 * injection rather than globals. This class serves as a unified global
28 * accessor to arbitrary services for use by legacy Drush code.
30 * Advice from Drupal 8's 'Drupal' class:
32 * This class exists only to support legacy code that cannot be dependency
33 * injected. If your code needs it, consider refactoring it to be object
34 * oriented, if possible. When this is not possible, and your code is more
35 * than a few non-reusable lines, it is recommended to instantiate an object
36 * implementing the actual logic.
39 * // Legacy procedural code.
40 * $object = drush_get_context('DRUSH_CLASS_LABEL');
43 * $object = Drush::service('label');
51 * The version of Drush from the drush.info file, or FALSE if not read yet.
55 protected static $version = false;
56 protected static $majorVersion = false;
57 protected static $minorVersion = false;
60 * The currently active container object, or NULL if not initialized yet.
62 * @var \League\Container\ContainerInterface|null
64 protected static $container;
67 * The Robo Runner -- manages and constructs all commandfile classes
71 protected static $runner;
74 * Return the current Drush version.
76 * n.b. Called before the DI container is initialized.
77 * Do not log, etc. here.
79 public static function getVersion()
81 if (!static::$version) {
82 $drush_info = static::drushReadDrushInfo();
83 static::$version = $drush_info['drush_version'];
85 return static::$version;
88 public static function getMajorVersion()
90 if (!static::$majorVersion) {
91 $drush_version = static::getVersion();
92 $version_parts = explode('.', $drush_version);
93 static::$majorVersion = $version_parts[0];
95 return static::$majorVersion;
98 public static function getMinorVersion()
100 if (!static::$minorVersion) {
101 $drush_version = static::getVersion();
102 $version_parts = explode('.', $drush_version);
103 static::$minorVersion = $version_parts[1];
105 return static::$minorVersion;
109 * Sets a new global container.
111 * @param \League\Container\Container $container
112 * A new container instance to replace the current.
114 public static function setContainer(ContainerInterface $container)
116 static::$container = $container;
120 * Unsets the global container.
122 public static function unsetContainer()
124 static::$container = null;
128 * Returns the currently active global container.
130 * @return \League\Container\ContainerInterface|null
132 * @throws RuntimeException
134 public static function getContainer()
136 if (static::$container === null) {
137 debug_print_backtrace();
138 throw new \RuntimeException('Drush::$container is not initialized yet. \Drupal::setContainer() must be called with a real container.');
140 return static::$container;
144 * Returns TRUE if the container has been initialized, FALSE otherwise.
148 public static function hasContainer()
150 return static::$container !== null;
154 * Get the current Symfony Console Application.
156 * @return Application
158 public static function getApplication()
160 return self::getContainer()->get('application');
164 * Return the Robo runner.
166 * @return \Robo\Runner
168 public static function runner()
170 if (!isset(static::$runner)) {
171 static::$runner = new \Robo\Runner();
173 return static::$runner;
177 * Retrieves a service from the container.
179 * Use this method if the desired service is not one of those with a dedicated
180 * accessor method below. If it is listed below, those methods are preferred
181 * as they can return useful type hints.
184 * The ID of the service to retrieve.
187 * The specified service.
189 public static function service($id)
191 return static::getContainer()->get($id);
195 * Indicates if a service is defined in the container.
198 * The ID of the service to check.
201 * TRUE if the specified service exists, FALSE otherwise.
203 public static function hasService($id)
205 // Check hasContainer() first in order to always return a Boolean.
206 return static::hasContainer() && static::getContainer()->has($id);
210 * Return command factory
212 * @return \Consolidation\AnnotatedCommand\AnnotatedCommandFactory
214 public static function commandFactory()
216 return static::service('commandFactory');
220 * Return the Drush logger object.
222 * @return LoggerInterface
224 public static function logger()
226 return static::service('logger');
230 * Return the configuration object
232 * @return \Drush\Config\DrushConfig
234 public static function config()
236 return static::service('config');
240 * @return SiteAliasManager
242 public static function aliasManager()
244 return static::service('site.alias.manager');
248 * Return the input object
250 * @return InputInterface
252 public static function input()
254 return static::service('input');
258 * Return the output object
260 * @return OutputInterface
262 public static function output()
264 return static::service('output');
268 * Return 'true' if we are in simulated mode
270 public static function simulate()
272 return \Drush\Drush::config()->get(\Robo\Config\Config::SIMULATE);
276 * Return 'true' if we are in backend mode
278 public static function backend()
280 return \Drush\Drush::config()->get(PreflightArgs::BACKEND);
284 * Return 'true' if we are in affirmative mode
286 public static function affirmative()
288 if (!static::hasService('input')) {
289 throw new \Exception('No input service available.');
291 return Drush::input()->getOption('yes') || (Drush::backend() && !Drush::negative());
295 * Return 'true' if we are in negative mode
297 public static function negative()
299 if (!static::hasService('input')) {
300 throw new \Exception('No input service available.');
302 return Drush::input()->getOption('no');
306 * Return 'true' if we are in verbose mode
308 public static function verbose()
310 if (!static::hasService('output')) {
313 return \Drush\Drush::output()->isVerbose();
317 * Return 'true' if we are in debug mode
319 public static function debug()
321 if (!static::hasService('output')) {
324 return \Drush\Drush::output()->isDebug();
328 * Return the Bootstrap Manager.
330 * @return \Drush\Boot\BootstrapManager
332 public static function bootstrapManager()
334 return static::service('bootstrap.manager');
338 * Return the Bootstrap object.
340 * @return \Drush\Boot\Boot
342 public static function bootstrap()
344 return static::bootstrapManager()->bootstrap();
347 public static function redispatchOptions($input = null)
349 $input = $input ?: static::input();
351 // $input->getOptions() returns an associative array of option => value
352 $options = $input->getOptions();
354 // The 'runtime.options' config contains a list of option names on th cli
355 $optionNamesFromCommandline = static::config()->get('runtime.options');
357 // Remove anything in $options that was not on the cli
358 $options = array_intersect_key($options, array_flip($optionNamesFromCommandline));
360 // Add in the 'runtime.context' items, which includes --include, --alias-path et. al.
361 return $options + array_filter(static::config()->get(PreflightArgs::DRUSH_RUNTIME_CONTEXT_NAMESPACE));
365 * Read the drush info file.
367 private static function drushReadDrushInfo()
369 $drush_info_file = dirname(__FILE__) . '/../drush.info';
371 return parse_ini_file($drush_info_file);