Skip to content

Commit 0d8108c

Browse files
Add a site spec parser and tests for same.
1 parent 5836287 commit 0d8108c

File tree

4 files changed

+330
-32
lines changed

4 files changed

+330
-32
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
namespace Drush\SiteAlias;
3+
4+
class SiteSpecParserTest extends \PHPUnit_Framework_TestCase
5+
{
6+
/**
7+
* @dataProvider parserTestValues
8+
*/
9+
public function testSiteSpecParser(
10+
$spec,
11+
$expected)
12+
{
13+
$root = dirname(__DIR__) . '/fixtures/sites/d8';
14+
$parser = new SiteSpecParser($root);
15+
16+
$result = $parser->parse($spec);
17+
if (isset($result['root'])) {
18+
$result['root'] = preg_replace('%.*/fixtures/%', '/fixtures/', $result['root']);
19+
}
20+
$this->assertEquals($expected, $result);
21+
}
22+
23+
/**
24+
* @dataProvider validSiteSpecs
25+
*/
26+
public function testValidSiteSpecs($spec)
27+
{
28+
$this->isSpecValid($spec, true);
29+
}
30+
31+
/**
32+
* @dataProvider invalidSiteSpecs
33+
*/
34+
public function testInvalidSiteSpecs($spec)
35+
{
36+
$this->isSpecValid($spec, false);
37+
}
38+
39+
protected function isSpecValid($spec, $expected)
40+
{
41+
$parser = new SiteSpecParser();
42+
43+
$result = $parser->valid($spec);
44+
$this->assertEquals($expected, $result);
45+
}
46+
47+
public static function validSiteSpecs()
48+
{
49+
return [
50+
[ '/path/to/drupal#sitename' ],
51+
[ 'user@server/path/to/drupal#sitename' ],
52+
[ 'user@server/path/to/drupal' ],
53+
[ 'user@server#sitename' ],
54+
[ '#sitename' ],
55+
];
56+
}
57+
58+
public static function invalidSiteSpecs()
59+
{
60+
return [
61+
[ 'sitename' ],
62+
[ '@/#' ],
63+
[ 'user@#sitename' ],
64+
[ '@server/path/to/drupal#sitename' ],
65+
[ 'user@server/path/to/drupal#' ],
66+
[ 'user@server/path/to/drupal#sitename!' ],
67+
[ 'user@server/path/to/drupal##sitename' ],
68+
[ 'user#server/path/to/drupal#sitename' ],
69+
];
70+
}
71+
72+
public static function parserTestValues()
73+
{
74+
return [
75+
[
76+
'user@server/path#somemultisite',
77+
[
78+
'remote-user' => 'user',
79+
'remote-server' => 'server',
80+
'root' => '/path',
81+
'sitename' => 'somemultisite',
82+
],
83+
],
84+
85+
[
86+
'user@server/path',
87+
[
88+
'remote-user' => 'user',
89+
'remote-server' => 'server',
90+
'root' => '/path',
91+
'sitename' => 'default',
92+
],
93+
],
94+
95+
[
96+
'/path#somemultisite',
97+
[
98+
'remote-user' => '',
99+
'remote-server' => '',
100+
'root' => '/path',
101+
'sitename' => 'somemultisite',
102+
],
103+
],
104+
105+
[
106+
'#somemultisite',
107+
[
108+
],
109+
],
110+
111+
[
112+
'#mymultisite',
113+
[
114+
'remote-user' => '',
115+
'remote-server' => '',
116+
'root' => '/fixtures/sites/d8',
117+
'sitename' => 'mymultisite',
118+
],
119+
],
120+
121+
];
122+
}
123+
}

src/SiteAlias/SiteAliasSpec.php

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/SiteAlias/SiteSpecParser.php

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<?php
2+
namespace Drush\SiteAlias;
3+
4+
/**
5+
* Parse a string that contains a site specification.
6+
*
7+
* Site specifications contain some of the following elements:
8+
* - remote-user
9+
* - remote-server
10+
* - path
11+
* - sitename
12+
*/
13+
class SiteSpecParser
14+
{
15+
protected $root;
16+
17+
/**
18+
* Constructor
19+
*
20+
* @param string $root
21+
* Drupal root (if provided)
22+
*/
23+
public function __construct($root = '')
24+
{
25+
$this->root = $root;
26+
}
27+
28+
/**
29+
* Parse a site specification
30+
*
31+
* @param string $spec
32+
* A site specification in one of the accepted forms:
33+
* - /path/to/drupal#sitename
34+
* - user@server/path/to/drupal#sitename
35+
* - user@server/path/to/drupal
36+
* - user@server#sitename
37+
* or, a site name:
38+
* - #sitename
39+
* @return array
40+
* A site specification array with the specified components filled in:
41+
* - remote-user
42+
* - remote-server
43+
* - path
44+
* - sitename
45+
* or, an empty array if the provided parameter is not a valid site spec.
46+
*/
47+
public function parse($spec)
48+
{
49+
return $this->validate($this->match($spec));
50+
}
51+
52+
/**
53+
* Determine if the provided specification is value.
54+
*
55+
* @param string $spec
56+
* @see parse()
57+
* @return bool
58+
*/
59+
public function valid($spec)
60+
{
61+
$result = $this->match($spec);
62+
return !empty($result);
63+
}
64+
65+
/**
66+
* Return the set of regular expression patterns that match the available
67+
* site specification formats.
68+
*
69+
* @return array
70+
* key: site specification regex
71+
* value: an array mapping from site specification component names to
72+
* the elements in the 'matches' array containing the data for that element.
73+
*/
74+
protected function patterns()
75+
{
76+
return [
77+
// /path/to/drupal#sitename
78+
'%^(/[^#]*)#([a-zA-Z0-9_-]+)$%' => [
79+
'root' => 1,
80+
'sitename' => 2,
81+
],
82+
// user@server/path/to/drupal#sitename
83+
'%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)(/[^#]*)#([a-zA-Z0-9_-]+)$%' => [
84+
'remote-user' => 1,
85+
'remote-server' => 2,
86+
'root' => 3,
87+
'sitename' => 4,
88+
],
89+
// user@server/path/to/drupal
90+
'%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)(/[^#]*)$%' => [
91+
'remote-user' => 1,
92+
'remote-server' => 2,
93+
'root' => 3,
94+
'sitename' => 'default', // Or '2' if sitename should be 'server'
95+
],
96+
// user@server#sitename
97+
'%^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)#([a-zA-Z0-9_-]+)$%' => [
98+
'remote-user' => 1,
99+
'remote-server' => 2,
100+
'sitename' => 3,
101+
],
102+
// #sitename
103+
'%^#([a-zA-Z0-9_-]+)$%' => [
104+
'sitename' => 1,
105+
],
106+
];
107+
}
108+
109+
/**
110+
* Run through all of the available regex patterns and determine if
111+
* any match the provided specification.
112+
*
113+
* @return array
114+
* @see parse()
115+
*/
116+
protected function match($spec)
117+
{
118+
foreach ($this->patterns() as $regex => $map) {
119+
if (preg_match($regex, $spec, $matches)) {
120+
return $this->mapResult($map, $matches);
121+
}
122+
}
123+
return [];
124+
}
125+
126+
/**
127+
* Inflate the provided array so that it always contains the required
128+
* elements.
129+
*
130+
* @return array
131+
* @see parse()
132+
*/
133+
protected function defaults($result = [])
134+
{
135+
$result += [
136+
'remote-user' => '',
137+
'remote-server' => '',
138+
'root' => '',
139+
'sitename' => '',
140+
];
141+
142+
return $result;
143+
}
144+
145+
/**
146+
* Take the data from the matches from the regular expression and
147+
* plug them into the result array per the info in the provided map.
148+
*
149+
* @param array $map
150+
* An array mapping from result key to matches index.
151+
* @param array $matches
152+
* The matched strings returned from preg_match
153+
* @return array
154+
* @see parse()
155+
*/
156+
protected function mapResult($map, $matches)
157+
{
158+
$result = [];
159+
160+
foreach ($map as $key => $index) {
161+
$value = is_string($index) ? $index : $matches[$index];
162+
$result[$key] = $value;
163+
}
164+
165+
if (empty($result)) {
166+
return [];
167+
}
168+
169+
return $this->defaults($result);
170+
}
171+
172+
/**
173+
* Validate the provided result. If the result is local, then it must
174+
* have a 'root'. If it does not, then fill in the root that was provided
175+
* to us in our consturctor.
176+
*
177+
* @param array $result
178+
* @see parse() result.
179+
* @return array
180+
* @see parse()
181+
*/
182+
protected function validate($result)
183+
{
184+
if (empty($result) || !empty($result['remote-server'])) {
185+
return $result;
186+
}
187+
188+
if (empty($result['root'])) {
189+
// TODO: should these throw an exception, so the user knows
190+
// why their site spec was invalid?
191+
if (empty($this->root) || !is_dir($this->root)) {
192+
return [];
193+
}
194+
195+
$path = $this->root . '/sites/' . $result['sitename'];
196+
if (!is_dir($path)) {
197+
return [];
198+
}
199+
200+
$result['root'] = $this->root;
201+
return $result;
202+
}
203+
204+
return $result;
205+
}
206+
}

0 commit comments

Comments
 (0)