Skip to content

Commit

Permalink
Merge 52caec1 into d7606cc
Browse files Browse the repository at this point in the history
  • Loading branch information
ademarco committed Jan 31, 2018
2 parents d7606cc + 52caec1 commit 6c48d1f
Show file tree
Hide file tree
Showing 9 changed files with 397 additions and 18 deletions.
23 changes: 12 additions & 11 deletions robo
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
#!/usr/bin/env php
<?php

/**
* if we're running from phar load the phar autoload,
* else let the script 'robo' search for the autoloader
* else let the script 'robo' search for the autoloader.
* If we cannot find a vendor/autoload.php file, then
* we will go ahead and try the phar.
*/
if (strpos(basename(__FILE__), 'phar')) {
require_once 'phar://robo.phar/vendor/autoload.php';
} else {
$autoloaderPath = 'phar://robo.phar/vendor/autoload.php';
if (!strpos(basename(__FILE__), 'phar')) {
if (file_exists(__DIR__.'/vendor/autoload.php')) {
require_once __DIR__.'/vendor/autoload.php';
$autoloaderPath = __DIR__.'/vendor/autoload.php';
} elseif (file_exists(__DIR__.'/../../autoload.php')) {
require_once __DIR__ . '/../../autoload.php';
} else {
require_once 'phar://robo.phar/vendor/autoload.php';
$autoloaderPath = __DIR__ . '/../../autoload.php';
}
}
$classLoader = require $autoloaderPath;
$runner = new \Robo\Runner();
$runner->setSelfUpdateRepository('consolidation/robo');
$runner
->setSelfUpdateRepository('consolidation/robo')
->setClassLoader($classLoader);
$statusCode = $runner->execute($_SERVER['argv']);
exit($statusCode);
exit($statusCode);
26 changes: 26 additions & 0 deletions src/ClassDiscovery/AbstractClassDiscovery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Robo\ClassDiscovery;

/**
* Class AbstractClassDiscovery
*
* @package Robo\ClassDiscovery
*/
abstract class AbstractClassDiscovery implements ClassDiscoveryInterface
{
/**
* @var string
*/
protected $searchPattern = '*.php';

/**
* {@inheritdoc}
*/
public function setSearchPattern($searchPattern)
{
$this->searchPattern = $searchPattern;

return $this;
}
}
30 changes: 30 additions & 0 deletions src/ClassDiscovery/ClassDiscoveryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace Robo\ClassDiscovery;

/**
* Interface ClassDiscoveryInterface
*
* @package Robo\Plugin\ClassDiscovery
*/
interface ClassDiscoveryInterface
{
/**
* @param $searchPattern
*
* @return $this
*/
public function setSearchPattern($searchPattern);

/**
* @return string[]
*/
public function getClasses();

/**
* @param $class
*
* @return string|null
*/
public function getFile($class);
}
112 changes: 112 additions & 0 deletions src/ClassDiscovery/RelativeNamespaceDiscovery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

namespace Robo\ClassDiscovery;

use Symfony\Component\Finder\Finder;
use Composer\Autoload\ClassLoader;

/**
* Class RelativeNamespaceDiscovery
*
* @package Robo\Plugin\ClassDiscovery
*/
class RelativeNamespaceDiscovery extends AbstractClassDiscovery
{
/**
* @var \Composer\Autoload\ClassLoader
*/
protected $classLoader;

/**
* @var string
*/
protected $relativeNamespace = '';

/**
* RelativeNamespaceDiscovery constructor.
*
* @param \Composer\Autoload\ClassLoader $classLoader
*/
public function __construct(ClassLoader $classLoader)
{
$this->classLoader = $classLoader;
}

/**
* @param string $relativeNamespace
*
* @return RelativeNamespaceDiscovery
*/
public function setRelativeNamespace($relativeNamespace)
{
$this->relativeNamespace = $relativeNamespace;

return $this;
}

/**
* @inheritDoc
*/
public function getClasses()
{
$classes = [];
$relativePath = $this->convertNamespaceToPath($this->relativeNamespace);

foreach ($this->classLoader->getPrefixesPsr4() as $baseNamespace => $directories) {
$directories = array_filter(array_map(function ($directory) use ($relativePath) {
return $directory.$relativePath;
}, $directories), 'is_dir');

if ($directories) {
foreach ($this->search($directories, $this->searchPattern) as $file) {
$relativePathName = $file->getRelativePathname();
$classes[] = $baseNamespace.$this->convertPathToNamespace($relativePath.'/'.$relativePathName);
}
}
}

return $classes;
}

/**
* {@inheritdoc}
*/
public function getFile($class)
{
return $this->classLoader->findFile($class);
}

/**
* @param $directories
* @param $pattern
*
* @return \Symfony\Component\Finder\Finder
*/
protected function search($directories, $pattern)
{
$finder = new Finder();
$finder->files()
->name($pattern)
->in($directories);

return $finder;
}

/**
* @param $path
*
* @return mixed
*/
protected function convertPathToNamespace($path)
{
return str_replace(['/', '.php'], ['\\', ''], trim($path, '/'));
}

/**
* @return string
*/
public function convertNamespaceToPath($namespace)
{
return '/'.str_replace("\\", '/', trim($namespace, '\\'));
}
}
15 changes: 12 additions & 3 deletions src/Robo.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Robo;

use Composer\Autoload\ClassLoader;
use League\Container\Container;
use League\Container\ContainerInterface;
use Robo\Common\ProcessExecutor;
Expand Down Expand Up @@ -127,10 +128,11 @@ public static function loadConfiguration($paths, $config = null)
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
* @param null|\Robo\Application $app
* @param null|ConfigInterface $config
* @param null|\Composer\Autoload\ClassLoader $classLoader
*
* @return \League\Container\Container|\League\Container\ContainerInterface
*/
public static function createDefaultContainer($input = null, $output = null, $app = null, $config = null)
public static function createDefaultContainer($input = null, $output = null, $app = null, $config = null, $classLoader = null)
{
// Do not allow this function to be called more than once.
if (static::hasContainer()) {
Expand All @@ -147,7 +149,7 @@ public static function createDefaultContainer($input = null, $output = null, $ap

// Set up our dependency injection container.
$container = new Container();
static::configureContainer($container, $app, $config, $input, $output);
static::configureContainer($container, $app, $config, $input, $output, $classLoader);

// Set the application dispatcher
$app->setDispatcher($container->get('eventDispatcher'));
Expand Down Expand Up @@ -175,8 +177,9 @@ public static function createDefaultContainer($input = null, $output = null, $ap
* @param ConfigInterface $config
* @param null|\Symfony\Component\Console\Input\InputInterface $input
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
* @param null|\Composer\Autoload\ClassLoader $classLoader
*/
public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, ConfigInterface $config, $input = null, $output = null)
public static function configureContainer(ContainerInterface $container, SymfonyApplication $app, ConfigInterface $config, $input = null, $output = null, $classLoader = null)
{
// Self-referential container refernce for the inflector
$container->add('container', $container);
Expand All @@ -189,6 +192,9 @@ public static function configureContainer(ContainerInterface $container, Symfony
if (!$output) {
$output = new \Symfony\Component\Console\Output\ConsoleOutput();
}
if (!$classLoader) {
$classLoader = new ClassLoader();
}
$config->set(Config::DECORATED, $output->isDecorated());
$config->set(Config::INTERACTIVE, $input->isInteractive());

Expand All @@ -197,6 +203,7 @@ public static function configureContainer(ContainerInterface $container, Symfony
$container->share('input', $input);
$container->share('output', $output);
$container->share('outputAdapter', \Robo\Common\OutputAdapter::class);
$container->share('classLoader', $classLoader);

// Register logging and related services.
$container->share('logStyler', \Robo\Log\RoboLogStyle::class);
Expand Down Expand Up @@ -245,6 +252,8 @@ function ($output, $message) use ($container) {
);
$container->share('commandFactory', \Consolidation\AnnotatedCommand\AnnotatedCommandFactory::class)
->withMethodCall('setCommandProcessor', ['commandProcessor']);
$container->share('relativeNamespaceDiscovery', \Robo\ClassDiscovery\RelativeNamespaceDiscovery::class)
->withArgument('classLoader');

// Deprecated: favor using collection builders to direct use of collections.
$container->add('collection', \Robo\Collection\Collection::class);
Expand Down
62 changes: 58 additions & 4 deletions src/Runner.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php
namespace Robo;

use Composer\Autoload\ClassLoader;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Input\StringInput;
use Robo\Contract\BuilderAwareInterface;
Expand Down Expand Up @@ -43,6 +44,16 @@ class Runner implements ContainerAwareInterface
*/
protected $selfUpdateRepository = null;

/**
* @var \Composer\Autoload\ClassLoader
*/
protected $classLoader = null;

/**
* @var string
*/
protected $commandFileRelativeNamespace = 'Robo\Commands';

/**
* Class Constructor
*
Expand Down Expand Up @@ -120,18 +131,19 @@ public function execute($argv, $appName = null, $appVersion = null, $output = nu
$app = Robo::createDefaultApplication($appName, $appVersion);
}
$commandFiles = $this->getRoboFileCommands($output);
return $this->run($argv, $output, $app, $commandFiles);
return $this->run($argv, $output, $app, $commandFiles, $this->classLoader);
}

/**
* @param null|\Symfony\Component\Console\Input\InputInterface $input
* @param null|\Symfony\Component\Console\Output\OutputInterface $output
* @param null|\Robo\Application $app
* @param array[] $commandFiles
* @param null|ClassLoader $classLoader
*
* @return int
*/
public function run($input = null, $output = null, $app = null, $commandFiles = [])
public function run($input = null, $output = null, $app = null, $commandFiles = [], $classLoader = null)
{
// Create default input and output objects if they were not provided
if (!$input) {
Expand All @@ -151,7 +163,7 @@ public function run($input = null, $output = null, $app = null, $commandFiles =
$userConfig = 'robo.yml';
$roboAppConfig = dirname(__DIR__) . '/robo.yml';
$config = Robo::createConfiguration([$userConfig, $roboAppConfig]);
$container = Robo::createDefaultContainer($input, $output, $app, $config);
$container = Robo::createDefaultContainer($input, $output, $app, $config, $classLoader);
$this->setContainer($container);
// Automatically register a shutdown function and
// an error handler when we provide the container.
Expand All @@ -169,6 +181,10 @@ public function run($input = null, $output = null, $app = null, $commandFiles =
$commandFiles = [];
}
}

$commandClasses = $this->discoverCommandClasses($this->commandFileRelativeNamespace);
$commandFiles = array_merge((array)$commandFiles, $commandClasses);

$this->registerCommandClasses($app, $commandFiles);

try {
Expand Down Expand Up @@ -212,6 +228,19 @@ public function registerCommandClasses($app, $commandClasses)
}
}

/**
* @param $relativeNamespace
*
* @return array|string[]
*/
protected function discoverCommandClasses($relativeNamespace)
{
/** @var \Robo\ClassDiscovery\RelativeNamespaceDiscovery $discovery */
$discovery = Robo::service('relativeNamespaceDiscovery');
$discovery->setRelativeNamespace($relativeNamespace);
return $discovery->getClasses();
}

/**
* @param \Robo\Application $app
* @param string|BuilderAwareInterface|ContainerAwareInterface $commandClass
Expand Down Expand Up @@ -456,10 +485,35 @@ public function getSelfUpdateRepository()
}

/**
* @param string $selfUpdateRepository
* @param $selfUpdateRepository
*
* @return $this
*/
public function setSelfUpdateRepository($selfUpdateRepository)
{
$this->selfUpdateRepository = $selfUpdateRepository;
return $this;
}

/**
* @param \Composer\Autoload\ClassLoader $classLoader
*
* @return $this
*/
public function setClassLoader(ClassLoader $classLoader)
{
$this->classLoader = $classLoader;
return $this;
}

/**
* @param string $relativeNamespace
*
* @return $this
*/
public function setCommandFileRelativeNamespace($relativeNamespace)
{
$this->commandFileRelativeNamespace = $relativeNamespace;
return $this;
}
}

0 comments on commit 6c48d1f

Please sign in to comment.