Skip to content

Commit

Permalink
Added posix permission selector (#1209)
Browse files Browse the repository at this point in the history
  • Loading branch information
siad007 committed Dec 24, 2019
1 parent d874743 commit 50d9440
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 2 deletions.
4 changes: 3 additions & 1 deletion classes/phing/tasks/ext/phpunit/PHPUnitTestRunner7.php
Expand Up @@ -296,7 +296,9 @@ public function getLastRiskyMessage()
*/
protected function composeMessage($message, PHPUnit\Framework\Test $test, \Throwable $e)
{
$message = "Test $message (" . $test->getName() . " in class " . get_class($test) . "): " . $e->getMessage();
$name = ($test instanceof \PHPUnit\Framework\TestCase ? $test->getName() : '');
$message = "Test {$message} ({$name} in class " . get_class($test) . ' ' . $e->getFile()
. ' on line ' . $e->getLine() . '): ' . $e->getMessage();

if ($e instanceof PHPUnit\Framework\ExpectationFailedException && $e->getComparisonFailure()) {
$message .= "\n" . $e->getComparisonFailure()->getDiff();
Expand Down
3 changes: 2 additions & 1 deletion classes/phing/tasks/ext/phpunit/PHPUnitTestRunner8.php
Expand Up @@ -348,7 +348,8 @@ public function addError(PHPUnit\Framework\Test $test, Throwable $e, float $time
protected function composeMessage($message, PHPUnit\Framework\Test $test, Throwable $e)
{
$name = ($test instanceof \PHPUnit\Framework\TestCase ? $test->getName() : '');
$message = "Test $message (" . $name . ' in class ' . get_class($test) . '): ' . $e->getMessage();
$message = "Test {$message} ({$name} in class " . get_class($test) . ' ' . $e->getFile()
. ' on line ' . $e->getLine() . '): ' . $e->getMessage();

if ($e instanceof PHPUnit\Framework\ExpectationFailedException && $e->getComparisonFailure()) {
$message .= "\n" . $e->getComparisonFailure()->getDiff();
Expand Down
82 changes: 82 additions & 0 deletions classes/phing/types/selectors/PosixPermissionsSelector.php
@@ -0,0 +1,82 @@
<?php
/**
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/

/**
* A selector that selects files based on their POSIX permissions.
*
* @author Siad Ardroumli <siad.ardroumli@gmail.com>
* @package phing.types.selectors
*/
class PosixPermissionsSelector implements FileSelector
{
/** @var string $permissions */
private $permissions;

/**
* Sets the permissions to look for.
* @param string $permissions the permissions string (rwxrwxrwx or octal)
*/
public function setPermissions(string $permissions): void
{
$this->validate($permissions);

if (strlen($permissions) === 3) {
$this->permissions = $permissions;
return;
}

$this->permissions = implode(
'',
array_map(
'array_sum',
array_chunk(
str_split(
strtr(
$permissions,
array_combine(
['r', 'w', 'x', '-'],
[4, 2, 1, 0]
)
)
),
3
)
)
);
}

private function validate(string $permissions): void
{
if (
preg_match('/^[0-7]{3}$/', $permissions) !== 1 &&
preg_match('/^[r-][w-][x-][r-][w-][x-][r-][w-][x-]$/', $permissions) !== 1
) {
throw new BuildException("the permissions attribute {$permissions} is invalid");
}
}

public function isSelected(PhingFile $basedir, $filename, PhingFile $file): bool
{
if ($this->permissions === null) {
throw new BuildException('the permissions attribute is required');
}

return decoct(fileperms($file->getPath()) & 0777) === $this->permissions;
}
}
8 changes: 8 additions & 0 deletions classes/phing/types/selectors/SelectorAware.php
Expand Up @@ -241,4 +241,12 @@ public function addSymlink(SymlinkSelector $selector)
{
$this->appendSelector($selector);
}

/**
* add a symlink selector entry on the selector list
*/
public function addPosixPermissions(PosixPermissionsSelector $selector)
{
$this->appendSelector($selector);
}
}
33 changes: 33 additions & 0 deletions docs/guide/en/source/appendixes/selectors.xml
Expand Up @@ -814,4 +814,37 @@
<para>The <literal>&lt;symlink></literal> selector selects only files that are symbolic links.</para>

</sect1>
<sect1 role="typedef" xml:id="PosixPermissions" xreflabel="&lt;PosixPermissions>">
<title>PosixPermissions Selector </title>

<para>The <literal>&lt;posixpermissions></literal> selector selects only files that have the given POSIX permissions.</para>

<table>
<title> Attributes for the <literal>&lt;posixpermissions></literal> selector </title>
<tgroup cols="4">
<colspec colname="name" colnum="1" colwidth="1.5*"/>
<colspec colname="description" colnum="2" colwidth="3*"/>
<colspec colname="default" colnum="3" colwidth="1*"/>
<colspec colname="required" colnum="4" colwidth="1*"/>
<thead>
<row>
<entry>Name</entry>
<entry>Description</entry>
<entry>Default</entry>
<entry>Required</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>permissions</literal></entry>
<entry>POSIX permissions in string (<literal>rwxrwxrwx</literal>) or
octal (<literal>777</literal>) format</entry>
<entry><literal>true</literal></entry>
<entry>Yes</entry>
</row>
</tbody>
</tgroup>
</table>

</sect1>
</appendix>
9 changes: 9 additions & 0 deletions etc/phing-grammar.rng
Expand Up @@ -360,6 +360,7 @@
<ref name="none_selector"/>
<ref name="not_selector"/>
<ref name="or_selector"/>
<ref name="posixpermissions_selector"/>
</choice>
</zeroOrMore>
</define>
Expand Down Expand Up @@ -632,6 +633,14 @@
</element>
</define>

<define name="posixpermissions_selector">
<element name="posixpermissions">
<oneOrMore>
<ref name="selectors"/>
</oneOrMore>
</element>
</define>

<!--
===========================================================================================================
Core types
Expand Down
107 changes: 107 additions & 0 deletions test/classes/phing/types/selectors/PosixPermissionsSelectorTest.php
@@ -0,0 +1,107 @@
<?php
/**
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/

use PHPUnit\Framework\TestCase;
use OsCondition as Os;

/**
* Class PosixPermissionsSelectorTest
*/
class PosixPermissionsSelectorTest extends TestCase
{
/** @var PosixPermissionsSelector $selector */
private $selector;

protected function setUp(): void
{
if (!Os::isFamily(Os::FAMILY_UNIX)) {
$this->markTestSkipped('Not POSIX');
}

$this->selector = new PosixPermissionsSelector();
}

public function tearDown(): void
{
$this->selector = null;
}

/**
* @test
*/
public function argumentRequired(): void
{
$this->expectException(BuildException::class);
$this->expectExceptionMessage('the permissions attribute is required');

$this->selector->isSelected(new PhingFile(__DIR__), '', new PhingFile(__FILE__));
}

/**
* @test
*/
public function isSelected(): void
{
$this->selector->setPermissions('rw-rw-r--');
$this->assertTrue(
$this->selector->isSelected(
new PhingFile(__DIR__),
(new PhingFile(__FILE__))->getName(),
new PhingFile(__FILE__)
),
'File permission is wrong. Actual ' . decoct(fileperms(__FILE__) & 0777)
);
}

/**
* @test
* @dataProvider illegalArgumentProvider
* @dataProvider legalArgumentProvider
* @param string $permission
* @param bool $throws
*/
public function argument(string $permission, $throws = false): void
{
if ($throws) {
$this->expectException(BuildException::class);
} else {
$this->expectNotToPerformAssertions();
}

$this->selector->setPermissions($permission);
}

public function legalArgumentProvider(): array
{
return [
'legal octal string' => ['750'],
'legal posix string' => ['rwxr-x---'],
];
}

public function illegalArgumentProvider(): array
{
return [
['855', true],
['4555', true],
['-rwxr-xr-x', true],
['xrwr-xr-x', true],
];
}
}

0 comments on commit 50d9440

Please sign in to comment.