Skip to content

Commit

Permalink
Merge pull request #3 from phpsu/feature/redirections
Browse files Browse the repository at this point in the history
✨ add redirections to collection
  • Loading branch information
ChrisB9 committed May 15, 2020
2 parents 7c2abd3 + 767b90a commit e1c3886
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/Collection/CollectionTuple.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ public function __toArray(): array
public function __toString(): string
{
/** @psalm-suppress ImplicitToStringCast **/
return sprintf(' %s %s', $this->join, $this->value);
return sprintf(' %s%s%s', $this->join, $this->value === '' ? '' : ' ', $this->value);
}
}
64 changes: 64 additions & 0 deletions src/Collection/Redirection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

namespace PHPSu\ShellCommandBuilder\Collection;

use PHPSu\ShellCommandBuilder\Definition\RedirectOperator;
use PHPSu\ShellCommandBuilder\Exception\ShellBuilderException;
use PHPSu\ShellCommandBuilder\ShellInterface;

final class Redirection extends AbstractCollection
{
/**
* @param string|ShellInterface $value
* @param bool $append
* @return $this
* @throws ShellBuilderException
*/
public function redirectOutput($value, bool $append): self
{
$this->tuple = CollectionTuple::create($value, $append ? RedirectOperator::STDOUT_LEFT_APPEND : RedirectOperator::STDOUT_LEFT_INSERT);
return $this;
}

/**
* @param string|ShellInterface $value
* @return $this
* @throws ShellBuilderException
*/
public function redirectInput($value): self
{
$this->tuple = CollectionTuple::create($value, RedirectOperator::STDIN_RIGHT);
return $this;
}

/**
* @param string|ShellInterface $value
* @return $this
* @throws ShellBuilderException
*/
public function redirectError($value): self
{
$this->tuple = CollectionTuple::create($value, RedirectOperator::FILE_DESCRIPTOR_ERR . RedirectOperator::STDOUT_LEFT_INSERT);
return $this;
}

/**
* @param string|ShellInterface $value
* @param bool $toLeft
* @return $this
* @throws ShellBuilderException
*/
public function redirectBetweenFiles($value, bool $toLeft): self
{
$this->tuple = CollectionTuple::create($value, $toLeft ? RedirectOperator::REDIRECT_LEFT : RedirectOperator::REDIRECT_RIGHT);
return $this;
}

public function redirectErrorToOutput(): self
{
$this->tuple = CollectionTuple::create('', RedirectOperator::ERR_TO_OUT_REDIRECT);
return $this;
}
}
105 changes: 79 additions & 26 deletions src/ShellBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PHPSu\ShellCommandBuilder\Collection\CollectionInterface;
use PHPSu\ShellCommandBuilder\Collection\CollectionTuple;
use PHPSu\ShellCommandBuilder\Collection\Pipeline;
use PHPSu\ShellCommandBuilder\Collection\Redirection;
use PHPSu\ShellCommandBuilder\Collection\ShellList;
use PHPSu\ShellCommandBuilder\Definition\ControlOperator;
use PHPSu\ShellCommandBuilder\Definition\GroupType;
Expand Down Expand Up @@ -36,10 +37,7 @@ public function createCommand(string $name, bool $withNewBuilder = false): Shell
*/
public function add($command): self
{
if (is_string($command)) {
$command = $this->createCommand($command);
}
$this->validateCommand($command, true);
$command = $this->parseCommand($command, true);
if (empty($this->commandList)) {
$this->commandList[] = $command;
return $this;
Expand All @@ -57,12 +55,8 @@ public function add($command): self
*/
public function and($command): self
{
if (is_string($command)) {
$command = $this->createCommand($command);
}
$this->validateCommand($command);
$list = new ShellList();
$list->addAnd($command);
$list->addAnd($this->parseCommand($command));
$this->commandList[] = $list;
return $this;
}
Expand All @@ -74,12 +68,8 @@ public function and($command): self
*/
public function or($command): self
{
if (is_string($command)) {
$command = $this->createCommand($command);
}
$this->validateCommand($command);
$list = new ShellList();
$list->addOr($command);
$list->addOr($this->parseCommand($command));
$this->commandList[] = $list;
return $this;
}
Expand All @@ -91,12 +81,8 @@ public function or($command): self
*/
public function pipe($command): self
{
if (is_string($command)) {
$command = $this->createCommand($command);
}
$this->validateCommand($command);
$list = new Pipeline();
$list->pipe($command);
$list->pipe($this->parseCommand($command));
$this->commandList[] = $list;
return $this;
}
Expand All @@ -108,16 +94,72 @@ public function pipe($command): self
*/
public function pipeWithForward($command): self
{
if (is_string($command)) {
$command = $this->createCommand($command);
}
$this->validateCommand($command);
$list = new Pipeline();
$list->pipeErrorForward($command);
$list->pipeErrorForward($this->parseCommand($command));
$this->commandList[] = $list;
return $this;
}

/**
* @param string|ShellInterface $command
* @param bool $append
* @return $this
* @throws ShellBuilderException
*/
public function redirectOutput($command, bool $append = false): self
{
$redirect = new Redirection();
$command = $this->parseCommand($command);
$this->commandList[] = $redirect->redirectOutput($command, $append);
return $this;
}

/**
* @param string|ShellInterface $command
* @return $this
* @throws ShellBuilderException
*/
public function redirectInput($command): self
{
$redirect = new Redirection();
$command = $this->parseCommand($command);
$this->commandList[] = $redirect->redirectInput($command);
return $this;
}

/**
* @param string|ShellInterface $command
* @return $this
* @throws ShellBuilderException
*/
public function redirectError($command): self
{
$redirect = new Redirection();
$command = $this->parseCommand($command);
$this->commandList[] = $redirect->redirectError($command);
return $this;
}

/**
* @param string|ShellInterface $command
* @param bool $toLeft
* @return $this
* @throws ShellBuilderException
*/
public function redirect($command, bool $toLeft = true): self
{
$redirect = new Redirection();
$command = $this->parseCommand($command);
$this->commandList[] = $redirect->redirectBetweenFiles($command, $toLeft);
return $this;
}

public function redirectErrorToOutput(): self
{
$this->commandList[] = (new Redirection())->redirectErrorToOutput();
return $this;
}

public function createGroup(bool $inSameShell = false): self
{
return new self($inSameShell ? GroupType::SAMESHELL_GROUP : GroupType::SUBSHELL_GROUP);
Expand All @@ -126,13 +168,24 @@ public function createGroup(bool $inSameShell = false): self
/**
* @param string|ShellInterface $command
* @param bool $allowEmpty
* @return ShellInterface
* @throws ShellBuilderException
*/
private function validateCommand($command, bool $allowEmpty = false): void
private function parseCommand($command, bool $allowEmpty = false): ShellInterface
{
if (!($command instanceof ShellInterface)) {
if (is_string($command)) {
$command = $this->createCommand($command);
}
try {
$this->validateCommand($command, $allowEmpty);
} catch (\TypeError $typeError) {
throw new ShellBuilderException('Provided the wrong type - only ShellCommand and ShellBuilder allowed');
}
return $command;
}

private function validateCommand(ShellInterface $command, bool $allowEmpty): void
{
if (!$allowEmpty && empty($this->commandList)) {
throw new ShellBuilderException('You have to first add a command before you can combine it');
}
Expand Down
69 changes: 69 additions & 0 deletions tests/ShellBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,75 @@ public function testBuilderToArray(): void
$this->assertEquals('c', $debug[0]['executable']);
}

public function testRedirectTo(): void
{
$builder = new ShellBuilder();
$builder->createCommand('echo')->addArgument('hello')->addToBuilder()
->redirectOutput('test.txt');
$this->assertEquals("echo 'hello' > test.txt", (string)$builder);
}

public function testRedirectToAppend(): void
{
$builder = new ShellBuilder();
$builder->createCommand('echo')->addArgument('hello')->addToBuilder()
->redirectOutput('test.txt', true);
$this->assertEquals("echo 'hello' >> test.txt", (string)$builder);
}

public function testRedirectToInput(): void
{
$builder = new ShellBuilder();
$builder->createCommand('mysql')->addArgument('database')->addToBuilder()
->redirectInput(
$builder->createCommand('mysqldump')
->addArgument('db', false)
->addNoSpaceArgument('.sql')
);
$this->assertEquals("mysql 'database' < mysqldump db.sql", (string)$builder);
}

public function testRedirectError(): void
{
$builder = new ShellBuilder();
$builder->createCommand('echo')->addArgument('not-existing', false)->addToBuilder()
->redirectError('/var/logs/errors');
$this->assertEquals("echo not-existing 2> /var/logs/errors", (string)$builder);
}

public function testRedirectBetweenFiles(): void
{
$builder = new ShellBuilder();
$builder->createCommand('echo')->addArgument('not-existing', false)->addToBuilder()
->redirect('/var/logs/errors');
$this->assertEquals("echo not-existing >& /var/logs/errors", (string)$builder);
}

public function testRedirectErrorToOutput(): void
{
$builder = new ShellBuilder();
$builder->createCommand('echo')->addArgument('not-existing', false)->addToBuilder()
->redirect('/var/logs/errors')
->redirectErrorToOutput()
;
$this->assertEquals("echo not-existing >& /var/logs/errors 2>&1", (string)$builder);
}


public function testRedirectBetweenFilesToRight(): void
{
$builder = new ShellBuilder();
$builder->createCommand('file.txt')->addToBuilder()
->redirect('ls', false);
$this->assertEquals("file.txt <& ls", (string)$builder);
}

public function testShellBuilderToStringEqualsShellCommandToString(): void
{
$builder = new ShellBuilder();
$this->assertEquals((string)$builder->createCommand('echo')->addToBuilder(), (string)$builder->createCommand('echo'));
}

public function testRemoteShellCommand(): void
{
$result = "ssh -F 'php://temp' 'hostc' 'mysqldump --opt --skip-comments --single-transaction --lock-tables=false -h '\''database'\'' -u '\''root'\'' -p '\''root'\'' '\''sequelmovie'\'' | (echo '\''CREATE DATABASE IF NOT EXISTS `sequelmovie2`;USE `sequelmovie2`;'\'' && cat)' | mysql -h '127.0.0.1' -P 2206 -u 'root' -p 'root'";
Expand Down

0 comments on commit e1c3886

Please sign in to comment.