diff --git a/core/console b/core/console index 9ee2d76..50e1afa 100755 --- a/core/console +++ b/core/console @@ -1,30 +1,28 @@ #!/usr/bin/env php consoleServiceYamlFiles(); -foreach ($service_files as $file) { +$services_finder = new ServicesFinder(); +foreach ($services_finder as $file) { $loader->load($file->getPathname()); } -$pass = new ConsoleCompilerPass(); +$pass = new CompilerPass(); $container->addCompilerPass($pass); $container->compile(); -$app = $container->get('drupal_console_app'); - +$app = $container->get('console.app'); $app->run(); diff --git a/core/core.console.services.yml b/core/core.console.services.yml index d379f47..6f70991 100644 --- a/core/core.console.services.yml +++ b/core/core.console.services.yml @@ -1,15 +1,22 @@ parameters: - # Make the class a property so we can change it for testing. - drupal_console_app.class: Drupal\Console\DrupalConsoleApp + # Make the class a property so we can change it for testing. + console.app.class: Drupal\Core\Console\Application services: - drupal_console_app: - class: "%drupal_console_app.class%" + console.app: + class: "%console.app.class%" + + console.bootstrap: + class: Drupal\Core\Console\Bootstrap + + console.command.cache_clear: + class: Drupal\Core\Console\Command\ClearCache + arguments: ['@console.bootstrap'] tags: - - { name: drupal_console } + - { name: console.command } - drupal_console.drupal_cron: - class: Drupal\Console\Command\DrupalCronCommand + console.command.run_cron: + class: Drupal\Core\Console\Command\RunCron + arguments: ['@console.bootstrap'] tags: - - { name: drupal_console.command } - - { name: drupal_console } + - { name: console.command } diff --git a/core/lib/Drupal/Console/Command/CommandBase.php b/core/lib/Drupal/Console/Command/CommandBase.php deleted file mode 100644 index 9adf5c4..0000000 --- a/core/lib/Drupal/Console/Command/CommandBase.php +++ /dev/null @@ -1,19 +0,0 @@ -addOption( - 'environment', 'e', InputOption::VALUE_REQUIRED, 'Kernel environment.', 'prod' - ); - parent::configure(); - } - - /** - * Bootstrap Drupal enough so that we can run commands which require it. - * - * @param InputInterface $input - * Command input object. - * @param OutputInterface $output - * Command output object - * - * @returns DrupalKernel|FALSE - * Booted kernel, or FALSE. - */ - protected function bootstrap(InputInterface $input, OutputInterface $output, Request $request = \NULL) { - // This defaults to 'prod.' - $env = $input->getOption('environment'); - try { - // This boot strategy ripped from drupal_handle_request(). - require_once __DIR__ . '/../../../../includes/bootstrap.inc'; - drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); - - $kernel = new DrupalKernel($env, \drupal_classloader(), TRUE); - $kernel->boot(); - - if (!$request) { - // Create a meaningful request object. We shouldn't really need this but - // Drupal complains if it's not present. - $request = Request::createFromGlobals(); - } - $container = $kernel->getContainer(); - $container->set('request', $request); - - // Don't ask me why we need this voodo. It's in drupal_handle_request(). - $container->get('request_stack')->push($request); - - drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); - return $kernel; - } - catch (\Exception $e) { - $formatter = $this->getHelperSet()->get('formatter'); - $error_messages = array( - 'Insufficient Drupal to proceed.', - 'This command requires a bootable Drupal installation.', - ); - $formatted_block = $formatter->formatBlock($error_messages, 'error', TRUE); - $output->writeln($formatted_block); - } - return FALSE; - } - -} diff --git a/core/lib/Drupal/Console/ConsoleCompilerPass.php b/core/lib/Drupal/Console/ConsoleCompilerPass.php deleted file mode 100644 index dccbc80..0000000 --- a/core/lib/Drupal/Console/ConsoleCompilerPass.php +++ /dev/null @@ -1,56 +0,0 @@ -findTaggedServiceIds('drupal_console.command'); - // Remove all services which aren't console-related. We don't want to - // instantiate any classes which have any dependencies other than those for - // console. -/* $services = $container->getServiceIds(); - foreach ($services as $service) { - if (!in_array($service, array('service_container', 'drupal_console_app'))) { - if (!in_array($service, $tagged_services)) { - $container->removeDefinition($service); - } - } - } -*/ - // Tell the container to add these services to the console app. - $definition = $container->getDefinition('drupal_console_app'); - foreach ($tagged_services as $id => $attributes) { - $definition->addMethodCall( - 'add', array(new Reference($id)) - ); - } - } - -} diff --git a/core/lib/Drupal/Console/Discovery/DrupalConsoleServicesFinder.php b/core/lib/Drupal/Console/Discovery/DrupalConsoleServicesFinder.php deleted file mode 100644 index 189d1cf..0000000 --- a/core/lib/Drupal/Console/Discovery/DrupalConsoleServicesFinder.php +++ /dev/null @@ -1,29 +0,0 @@ -inDrupalCore() - ->inContrib() - ->excludeVendor() - // Only files, no directories. - ->files() - // Don't try to look in forbidden places. - ->ignoreUnreadableDirs() - // Ignore .git directories. - ->ignoreVCS(TRUE); - - // We want console service YAML files. - $this->name('*.console.services.yml'); - - return $this->getIterator(); - } - - -} \ No newline at end of file diff --git a/core/lib/Drupal/Console/DrupalConsoleApp.php b/core/lib/Drupal/Console/DrupalConsoleApp.php deleted file mode 100644 index 2f2f301..0000000 --- a/core/lib/Drupal/Console/DrupalConsoleApp.php +++ /dev/null @@ -1,73 +0,0 @@ -inDrupalCore() - ->inContrib() - ->excludeVendor() - // Only files, no directories. - ->files() - // Don't try to look in forbidden places. - ->ignoreUnreadableDirs() - // Ignore .git directories. - ->ignoreVCS(TRUE); - - // We want console service YAML files. - $finder->name('*.console.services.yml'); - - // We keep a class file resolver around so we can use it in both discovery - // and loading, since it stores what it has looked up. - $resolver = new FileClassResolver(); - - // Use IsSubclassFilterIterator to find classes which are subclasses of - // CommandBase. - $filter_iterator = new IsSubclassFilterIterator( - $finder->getIterator(), - 'Drupal\\Console\\Command\\CommandBase', - $resolver - ); - - // Add the commands we found to the app. - foreach ($filter_iterator as $file) { - $class = $resolver->classInFile($file->getPathName()); - $this->add(new $class()); - } - - return $this; - } - -} diff --git a/core/lib/Drupal/Core/Console/Application.php b/core/lib/Drupal/Core/Console/Application.php new file mode 100644 index 0000000..aa7deed --- /dev/null +++ b/core/lib/Drupal/Core/Console/Application.php @@ -0,0 +1,21 @@ +getOption('environment'); + try { + require_once __DIR__ . '/../../../includes/bootstrap.inc'; + drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION); + + $kernel = new DrupalKernel($env, \drupal_classloader(), TRUE); + $kernel->boot(); + + if (!$request) { + // Create a meaningful request object. We shouldn't really need this but + // Drupal complains if it's not present. + $request = Request::createFromGlobals(); + } + $container = $kernel->getContainer(); + $container->set('request', $request); + $container->get('request_stack')->push($request); + + drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE); + return $kernel; + } + catch (\Exception $e) { + /** @var \Symfony\Component\Console\Helper\FormatterHelper $formatter */ + $formatter = $command->getHelperSet()->get('formatter'); + $error_messages = array( + 'Insufficient Drupal to proceed.', + 'This command requires a bootable Drupal installation.', + ); + $formatted_block = $formatter->formatBlock($error_messages, 'error', TRUE); + $output->writeln($formatted_block); + } + return FALSE; + } + +} diff --git a/core/lib/Drupal/Core/Console/BootstrapInterface.php b/core/lib/Drupal/Core/Console/BootstrapInterface.php new file mode 100644 index 0000000..6945de7 --- /dev/null +++ b/core/lib/Drupal/Core/Console/BootstrapInterface.php @@ -0,0 +1,33 @@ +setName('drupal:cache-clear') + ->setAliases(array('cc')) + ->setDescription('Clears all caches.'); + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) { + $kernel = $this->bootstrap->bootstrap($this, $input, $output); + if ($kernel) { + drupal_flush_all_caches(); + $output->writeln('Caches cleared.'); + } + } + +} diff --git a/core/lib/Drupal/Core/Console/Command/CommandBootstrapBase.php b/core/lib/Drupal/Core/Console/Command/CommandBootstrapBase.php new file mode 100644 index 0000000..ec91fa8 --- /dev/null +++ b/core/lib/Drupal/Core/Console/Command/CommandBootstrapBase.php @@ -0,0 +1,53 @@ +bootstrap = $bootstrap; + } + + /** + * {@inheritdoc} + */ + protected function configure() { + parent::configure(); + $this + ->addOption( + 'environment', 'e', InputOption::VALUE_REQUIRED, 'Kernel environment.', 'prod' + ); + } + +} diff --git a/core/lib/Drupal/Console/Command/DrupalCronCommand.php b/core/lib/Drupal/Core/Console/Command/RunCron.php similarity index 61% rename from core/lib/Drupal/Console/Command/DrupalCronCommand.php rename to core/lib/Drupal/Core/Console/Command/RunCron.php index 58470e6..f47cedc 100644 --- a/core/lib/Drupal/Console/Command/DrupalCronCommand.php +++ b/core/lib/Drupal/Core/Console/Command/RunCron.php @@ -2,16 +2,18 @@ /** * @file - * Command class for drupal:cron. + * Contains \Drupal\Core\Console\Command\RunCron. */ -namespace Drupal\Console\Command; +namespace Drupal\Core\Console\Command; -use Drupal\Console\Command\CommandBootstrapBase; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -class DrupalCronCommand extends CommandBootstrapBase { +/** + * Runs cron from the console. + */ +class RunCron extends CommandBootstrapBase { /** * {@inheritdoc} @@ -20,20 +22,21 @@ protected function configure() { parent::configure(); $this ->setName('drupal:cron') - ->setDescription('Perform a cron run.'); + ->setAliases(array('cron')) + ->setDescription('Performs a cron run.'); } /** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { - $kernel = $this->bootstrap($input, $output); + $kernel = $this->bootstrap->bootstrap($this, $input, $output); if ($kernel) { $output->writeln('Running cron...'); + /** @var \Drupal\Core\CronInterface $cron */ $cron = $kernel->getContainer()->get('cron'); $cron->run(); $output->writeln('Done.'); - return; } } diff --git a/core/lib/Drupal/Core/Console/CompilerPass.php b/core/lib/Drupal/Core/Console/CompilerPass.php new file mode 100644 index 0000000..39fda13 --- /dev/null +++ b/core/lib/Drupal/Core/Console/CompilerPass.php @@ -0,0 +1,42 @@ +findTaggedServiceIds('console.command'); + $definition = $container->getDefinition('console.app'); + foreach (array_keys($tagged_services) as $id) { + $definition->addMethodCall( + 'add', array(new Reference($id)) + ); + } + } + +} diff --git a/core/lib/Drupal/Core/Console/ServicesFinder.php b/core/lib/Drupal/Core/Console/ServicesFinder.php new file mode 100644 index 0000000..7038b10 --- /dev/null +++ b/core/lib/Drupal/Core/Console/ServicesFinder.php @@ -0,0 +1,24 @@ +inDrupalCore() + ->inContrib() + ->excludeVendor() + ->files() + ->ignoreUnreadableDirs() + ->ignoreVCS(TRUE) + ->name('*.console.services.yml'); + } + +} \ No newline at end of file diff --git a/core/lib/Drupal/Core/Discovery/DrupalFinder.php b/core/lib/Drupal/Core/Discovery/DrupalFinder.php index 016b0e5..9baf4a6 100644 --- a/core/lib/Drupal/Core/Discovery/DrupalFinder.php +++ b/core/lib/Drupal/Core/Discovery/DrupalFinder.php @@ -2,7 +2,7 @@ /** * @file - * Contains Drupal\Core\Discovery\DrupalFinder. + * Contains \Drupal\Core\Discovery\DrupalFinder. */ namespace Drupal\Core\Discovery; @@ -10,87 +10,86 @@ use Symfony\Component\Finder\Finder; /** - * Drupal use-cases for Symfony's Finder component. + * Provides a finder with helpers for searching Drupal directories. */ class DrupalFinder extends Finder { - protected $drupalRoot; + /** + * The path to the Drupal root directory. + * + * @var string + */ + protected $drupalRoot = ''; /** - * Constructor for DrupalFinder. + * Constructs a new class instance. * * @param string $drupal_root * (optional) Path to initialize as the root of the Drupal installation. - * - * @todo: Come up with a way to avoid dirname(). */ public function __construct($drupal_root = NULL) { parent::__construct(); if (!$drupal_root) { - $drupal_root = realpath(dirname(dirname(dirname(dirname(dirname(dirname(__FILE__))))))); + $drupal_root = __DIR__ . '/../../../../..'; } $this->drupalRoot = $drupal_root; } /** - * Path to the root of the Drupal installation. + * Gets the path to the root of the Drupal installation. * * @return string - * Path to the root of the Drupal installation. + * The path to the root of the Drupal installation. */ - public function drupalRoot() { + public function getDrupalRootPath() { return $this->drupalRoot; } /** - * Path to the Drupal installation's core directory. + * Gets the path to the Drupal installation's ./core directory. * * @return string - * Path to the Drupal installation's core directory. + * The path to the Drupal installation's core directory. */ - public function drupalCore() { - return $this->drupalRoot . '/core'; + public function getDrupalCorePath() { + return $this->getDrupalRootPath() . '/core'; } /** - * Set iterator to search the Drupal root directory. + * Sets the iterator to search the Drupal root directory. * - * @return Drupal\Core\Discovery\DrupalFinder - * Fluent interface. + * @return $this */ public function inDrupalRoot() { - return $this->in($this->drupalRoot); + return $this->in($this->getDrupalRootPath()); } /** - * Set iterator to search the Drupal core directory. + * Sets the iterator to search the Drupal core directory. * - * @return Drupal\Core\Discovery\DrupalFinder - * Fluent interface. + * @return $this */ public function inDrupalCore() { - return $this->in($this->drupalCore()); + return $this->in($this->getDrupalCorePath()); } /** - * Set iterator to search within Drupal's contrib directories. + * Sets the iterator to search within Drupal's contrib directories. * - * @return Drupal\Core\Discovery\DrupalFinder - * Fluent interface. + * @return $this */ public function inContrib() { - $this->in($this->drupalRoot . '/modules'); - return $this->in($this->drupalRoot . '/sites'); + $this->in($this->getDrupalRootPath() . '/modules'); + return $this->in($this->getDrupalRootPath() . '/sites'); } /** - * Set iterator to exclude Composer's vendor directory. + * Sets the iterator to exclude Composer's vendor directory. * - * @return Drupal\Core\Discovery\DrupalFinder - * Fluent interface. + * @return $this */ public function excludeVendor() { - return $this->exclude($this->drupalCore() . '/vendor'); + return $this->exclude($this->getDrupalCorePath() . '/vendor'); } } diff --git a/core/lib/Drupal/Core/DrupalKernelInterface.php b/core/lib/Drupal/Core/DrupalKernelInterface.php index 1e2ed07..a0c8140 100644 --- a/core/lib/Drupal/Core/DrupalKernelInterface.php +++ b/core/lib/Drupal/Core/DrupalKernelInterface.php @@ -49,7 +49,7 @@ public function getServiceProviders($origin); /** * Gets the current container. * - * @return ContainerInterface A ContainerInterface instance + * @return \Symfony\Component\DependencyInjection\ContainerInterface A ContainerInterface instance */ public function getContainer(); diff --git a/core/tests/Drupal/Tests/Core/Console/ApplicationTest.php b/core/tests/Drupal/Tests/Core/Console/ApplicationTest.php new file mode 100644 index 0000000..7b0ad8c --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Console/ApplicationTest.php @@ -0,0 +1,25 @@ +bootstrap = $this->getMock('\Drupal\Core\Console\BootstrapInterface'); + + $this->command = new ClearCache($this->bootstrap); + } + + /** + * @covers ::execute + */ + public function testExecute() { + $input = $this->getMock('\Symfony\Component\Console\Input\InputInterface'); + + $output = $this->getMock('\Symfony\Component\Console\Output\OutputInterface'); + $output->expects($this->atLeastOnce()) + ->method('writeln'); + + $kernel = $this->getMock('\Drupal\Core\DrupalKernelInterface'); + + $this->bootstrap->expects($this->once()) + ->method('bootstrap') + ->with($this->command, $input, $output) + ->will($this->returnValue($kernel)); + + $method = new \ReflectionMethod($this->command, 'execute'); + $method->setAccessible(TRUE); + $method->invoke($this->command, $input, $output); + } + +} + +} + +namespace { + +if (!function_exists('drupal_flush_all_caches')) { + function drupal_flush_all_caches() { + } +} + +} diff --git a/core/tests/Drupal/Tests/Core/Console/Command/RunCronTest.php b/core/tests/Drupal/Tests/Core/Console/Command/RunCronTest.php new file mode 100644 index 0000000..2848145 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Console/Command/RunCronTest.php @@ -0,0 +1,79 @@ +bootstrap = $this->getMock('\Drupal\Core\Console\BootstrapInterface'); + + $this->command = new RunCron($this->bootstrap); + } + + /** + * @covers ::execute + */ + public function testExecute() { + $input = $this->getMock('\Symfony\Component\Console\Input\InputInterface'); + + $output = $this->getMock('\Symfony\Component\Console\Output\OutputInterface'); + $output->expects($this->atLeastOnce()) + ->method('writeln'); + + $cron = $this->getMock('\Drupal\Core\CronInterface'); + $cron->expects($this->once()) + ->method('run'); + + $container = $this->getMock('\Symfony\Component\DependencyInjection\ContainerInterface'); + $container->expects($this->once()) + ->method('get') + ->with('cron') + ->will($this->returnValue($cron)); + + $kernel = $this->getMock('\Drupal\Core\DrupalKernelInterface'); + $kernel->expects($this->atLeastOnce()) + ->method('getContainer') + ->will($this->returnValue($container)); + + $this->bootstrap->expects($this->once()) + ->method('bootstrap') + ->with($this->command, $input, $output) + ->will($this->returnValue($kernel)); + + $method = new \ReflectionMethod($this->command, 'execute'); + $method->setAccessible(TRUE); + $method->invoke($this->command, $input, $output); + } + +} diff --git a/core/tests/Drupal/Tests/Core/Console/CompilerPassTest.php b/core/tests/Drupal/Tests/Core/Console/CompilerPassTest.php new file mode 100644 index 0000000..e7442ee --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Console/CompilerPassTest.php @@ -0,0 +1,75 @@ +command = new CompilerPass(); + } + + /** + * @covers ::process + */ + public function testProcess() { + $service_ids = array($this->randomName(), $this->randomName()); + + $input = $this->getMock('\Symfony\Component\Console\Input\InputInterface'); + + $output = $this->getMock('\Symfony\Component\Console\Output\OutputInterface'); + $output->expects($this->atLeastOnce()) + ->method('writeln'); + + $definition = $this->getMockBuilder('\Symfony\Component\DependencyInjection\Definition') + ->disableOriginalConstructor() + ->getMock(); + $definition->expects($this->exactly(count($service_ids))) + ->method('addMethodCall') + ->with('add', array($this->isInstanceOf('\Symfony\Component\DependencyInjection\Reference'))); + + $container_builder = $this->getMockBuilder('\Symfony\Component\DependencyInjection\ContainerBuilder') + ->disableOriginalConstructor() + ->getMock(); + $container_builder->expects($this->once()) + ->method('findTaggedServiceIds') + ->with('console.command') + ->will($this->returnValue(array_fill_keys($service_ids, array()))); + $container_builder->expects($this->once()) + ->method('getDefinition') + ->with('console.app') + ->will($this->returnValue($definition)); + + $method = new \ReflectionMethod($this->command, 'execute'); + $method->setAccessible(TRUE); + $method->invoke($this->command, $input, $output); + } + +} diff --git a/core/tests/Drupal/Tests/Core/Console/ServicesFinderTest.php b/core/tests/Drupal/Tests/Core/Console/ServicesFinderTest.php new file mode 100644 index 0000000..47aac01 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Console/ServicesFinderTest.php @@ -0,0 +1,32 @@ +getRealPath(); + $this->assertFileExists($file->getRealPath()); + } + $this->assertNotCount(0, $files); + } + +} diff --git a/core/vendor/symfony/console/Symfony/Component/Console/Resources/bin/hiddeninput.exe b/core/vendor/symfony/console/Symfony/Component/Console/Resources/bin/hiddeninput.exe index 9f4a2aa6357a7dd48f810a66982dc0f78a1c27f6..b59fd5b7935e856dc92af806dd500f9346b0e92a 100644 GIT binary patch delta 10 Rcmez5{?UCx>Bh1eWdI;x1w8-& delta 12 Tcmez9{>gnpDI@R3(i&v|Cy)h7