Skip to content

Commit

Permalink
Add a site spec parser and tests for same.
Browse files Browse the repository at this point in the history
  • Loading branch information
greg-1-anderson committed Aug 11, 2017
1 parent 5836287 commit 0d8108c
Show file tree
Hide file tree
Showing 4 changed files with 330 additions and 32 deletions.
1 change: 1 addition & 0 deletions isolation/fixtures/sites/d8/sites/mymultisite/settings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php
123 changes: 123 additions & 0 deletions isolation/tests/SiteSpecParserTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
namespace Drush\SiteAlias;

class SiteSpecParserTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider parserTestValues
*/
public function testSiteSpecParser(
$spec,
$expected)
{
$root = dirname(__DIR__) . '/fixtures/sites/d8';
$parser = new SiteSpecParser($root);

$result = $parser->parse($spec);
if (isset($result['root'])) {
$result['root'] = preg_replace('%.*/fixtures/%', '/fixtures/', $result['root']);
}
$this->assertEquals($expected, $result);
}

/**
* @dataProvider validSiteSpecs
*/
public function testValidSiteSpecs($spec)
{
$this->isSpecValid($spec, true);
}

/**
* @dataProvider invalidSiteSpecs
*/
public function testInvalidSiteSpecs($spec)
{
$this->isSpecValid($spec, false);
}

protected function isSpecValid($spec, $expected)
{
$parser = new SiteSpecParser();

$result = $parser->valid($spec);
$this->assertEquals($expected, $result);
}

public static function validSiteSpecs()
{
return [
[ '/path/to/drupal#sitename' ],
[ 'user@server/path/to/drupal#sitename' ],
[ 'user@server/path/to/drupal' ],
[ 'user@server#sitename' ],
[ '#sitename' ],
];
}

public static function invalidSiteSpecs()
{
return [
[ 'sitename' ],
[ '@/#' ],
[ 'user@#sitename' ],
[ '@server/path/to/drupal#sitename' ],
[ 'user@server/path/to/drupal#' ],
[ 'user@server/path/to/drupal#sitename!' ],
[ 'user@server/path/to/drupal##sitename' ],
[ 'user#server/path/to/drupal#sitename' ],
];
}

public static function parserTestValues()
{
return [
[
'user@server/path#somemultisite',
[
'remote-user' => 'user',
'remote-server' => 'server',
'root' => '/path',
'sitename' => 'somemultisite',
],
],

[
'user@server/path',
[
'remote-user' => 'user',
'remote-server' => 'server',
'root' => '/path',
'sitename' => 'default',
],
],

[
'/path#somemultisite',
[
'remote-user' => '',
'remote-server' => '',
'root' => '/path',
'sitename' => 'somemultisite',
],
],

[
'#somemultisite',
[
],
],

[
'#mymultisite',
[
'remote-user' => '',
'remote-server' => '',
'root' => '/fixtures/sites/d8',
'sitename' => 'mymultisite',
],
],

];
}
}
32 changes: 0 additions & 32 deletions src/SiteAlias/SiteAliasSpec.php

This file was deleted.

206 changes: 206 additions & 0 deletions src/SiteAlias/SiteSpecParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
<?php
namespace Drush\SiteAlias;

/**
* Parse a string that contains a site specification.
*
* Site specifications contain some of the following elements:
* - remote-user
* - remote-server
* - path
* - sitename
*/
class SiteSpecParser
{
protected $root;

/**
* Constructor
*
* @param string $root
* Drupal root (if provided)
*/
public function __construct($root = '')
{
$this->root = $root;
}

/**
* Parse a site specification
*
* @param string $spec
* A site specification in one of the accepted forms:
* - /path/to/drupal#sitename
* - user@server/path/to/drupal#sitename
* - user@server/path/to/drupal
* - user@server#sitename
* or, a site name:
* - #sitename
* @return array
* A site specification array with the specified components filled in:
* - remote-user
* - remote-server
* - path
* - sitename
* or, an empty array if the provided parameter is not a valid site spec.
*/
public function parse($spec)
{
return $this->validate($this->match($spec));
}

/**
* Determine if the provided specification is value.
*
* @param string $spec
* @see parse()
* @return bool
*/
public function valid($spec)
{
$result = $this->match($spec);
return !empty($result);
}

/**
* Return the set of regular expression patterns that match the available
* site specification formats.
*
* @return array
* key: site specification regex
* value: an array mapping from site specification component names to
* the elements in the 'matches' array containing the data for that element.
*/
protected function patterns()
{
return [
// /path/to/drupal#sitename
'%^(/[^#]*)#([a-zA-Z0-9_-]+)$%' => [
'root' => 1,
'sitename' => 2,
],
// user@server/path/to/drupal#sitename
'%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)(/[^#]*)#([a-zA-Z0-9_-]+)$%' => [
'remote-user' => 1,
'remote-server' => 2,
'root' => 3,
'sitename' => 4,
],
// user@server/path/to/drupal
'%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)(/[^#]*)$%' => [
'remote-user' => 1,
'remote-server' => 2,
'root' => 3,
'sitename' => 'default', // Or '2' if sitename should be 'server'
],
// user@server#sitename
'%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)#([a-zA-Z0-9_-]+)$%' => [
'remote-user' => 1,
'remote-server' => 2,
'sitename' => 3,
],
// #sitename
'%^#([a-zA-Z0-9_-]+)$%' => [
'sitename' => 1,
],
];
}

/**
* Run through all of the available regex patterns and determine if
* any match the provided specification.
*
* @return array
* @see parse()
*/
protected function match($spec)
{
foreach ($this->patterns() as $regex => $map) {
if (preg_match($regex, $spec, $matches)) {
return $this->mapResult($map, $matches);
}
}
return [];
}

/**
* Inflate the provided array so that it always contains the required
* elements.
*
* @return array
* @see parse()
*/
protected function defaults($result = [])
{
$result += [
'remote-user' => '',
'remote-server' => '',
'root' => '',
'sitename' => '',
];

return $result;
}

/**
* Take the data from the matches from the regular expression and
* plug them into the result array per the info in the provided map.
*
* @param array $map
* An array mapping from result key to matches index.
* @param array $matches
* The matched strings returned from preg_match
* @return array
* @see parse()
*/
protected function mapResult($map, $matches)
{
$result = [];

foreach ($map as $key => $index) {
$value = is_string($index) ? $index : $matches[$index];
$result[$key] = $value;
}

if (empty($result)) {
return [];
}

return $this->defaults($result);
}

/**
* Validate the provided result. If the result is local, then it must
* have a 'root'. If it does not, then fill in the root that was provided
* to us in our consturctor.
*
* @param array $result
* @see parse() result.
* @return array
* @see parse()
*/
protected function validate($result)
{
if (empty($result) || !empty($result['remote-server'])) {
return $result;
}

if (empty($result['root'])) {
// TODO: should these throw an exception, so the user knows
// why their site spec was invalid?
if (empty($this->root) || !is_dir($this->root)) {
return [];
}

$path = $this->root . '/sites/' . $result['sitename'];
if (!is_dir($path)) {
return [];
}

$result['root'] = $this->root;
return $result;
}

return $result;
}
}

0 comments on commit 0d8108c

Please sign in to comment.